]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Add API call 'status/activity'.
authorDeltaMikeCharlie <127641886+DeltaMikeCharlie@users.noreply.github.com>
Sun, 1 Jun 2025 22:27:58 +0000 (08:27 +1000)
committerFlole <Flole998@users.noreply.github.com>
Mon, 2 Jun 2025 00:47:08 +0000 (02:47 +0200)
src/api/api_status.c
src/dvr/dvr.h
src/dvr/dvr_db.c
src/epggrab.c
src/epggrab.h
src/epggrab/otamux.c
src/input/mpegts/mpegts_mux_sched.c
src/input/mpegts/mpegts_mux_sched.h
src/tcp.c
src/tcp.h

index 9b8e5c99a954c160e8f54fea11d93b3d684b51c6..cd48e88ba6d0d7b2512b231ca98e6625ba9d4095 100644 (file)
@@ -26,6 +26,8 @@
 #include "api.h"
 #include "tcp.h"
 #include "input.h"
+#include "epggrab.h"  //Needed to get the next EPG grab times
+#include "dvr/dvr.h"  //Needed to get the next schedule dvr time
 
 static int
 api_status_inputs
@@ -171,6 +173,75 @@ api_status_input_clear_stats
   return 0;
 }
 
+static int
+api_status_activity
+  ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+  htsmsg_t *cats;
+  time_t temp_earliest = 0;
+  time_t temp_dvr = 0;
+  time_t temp_ota = 0;
+  time_t temp_int = 0;
+  time_t temp_mux = 0;
+  th_subscription_t *ths;
+  uint32_t subscriptionCount = 0;
+
+  temp_dvr = dvr_entry_find_earliest();
+
+  //Only evaluate the OTA grabber cron if there are active OTA modules.
+  if(epggrab_count_type(EPGGRAB_OTA))
+  {
+    temp_ota = epggrab_get_next_ota();
+  }
+  
+  //Only evaluate the internal grabber cron if there are active internal modules.
+  if(epggrab_count_type(EPGGRAB_INT))
+  {
+    temp_int = epggrab_get_next_int();
+  }
+  
+  temp_mux = mpegts_mux_sched_next();
+
+  temp_earliest = temp_dvr;
+
+  if(temp_ota && ((temp_ota < temp_earliest) || (temp_earliest == 0)))
+  {
+    temp_earliest = temp_ota;
+  }
+
+  if(temp_int && ((temp_int < temp_earliest) || (temp_earliest == 0)))
+  {
+    temp_earliest = temp_int;
+  }
+
+  if(temp_mux && ((temp_mux < temp_earliest) || (temp_earliest == 0)))
+  {
+    temp_earliest = temp_mux;
+  }
+
+  cats = htsmsg_create_map();
+  htsmsg_add_s64(cats, "dvr", temp_dvr);
+  htsmsg_add_s64(cats, "ota_grabber", temp_ota);
+  htsmsg_add_s64(cats, "int_grabber", temp_int);
+  htsmsg_add_s64(cats, "mux_scheduler", temp_mux);
+
+  tvh_mutex_lock(&global_lock);
+  LIST_FOREACH(ths, &subscriptions, ths_global_link) {
+    subscriptionCount++;
+  }
+  tvh_mutex_unlock(&global_lock);
+
+  *resp = htsmsg_create_map();
+  htsmsg_add_s64(*resp, "current_time", gclk());
+  htsmsg_add_s64(*resp, "next_activity", temp_earliest);
+  htsmsg_add_msg(*resp, "activities", cats);
+  htsmsg_add_u32(*resp, "subscription_count", subscriptionCount);
+  htsmsg_add_u32(*resp, "connection_count", tcp_server_connections_count());
+
+  return 0;
+
+}
+
 void api_status_init ( void )
 {
   static api_hook_t ah[] = {
@@ -178,6 +249,7 @@ void api_status_init ( void )
     { "status/subscriptions", ACCESS_ADMIN, api_status_subscriptions, NULL },
     { "status/inputs",        ACCESS_ADMIN, api_status_inputs, NULL },
     { "status/inputclrstats", ACCESS_ADMIN, api_status_input_clear_stats, NULL },
+    { "status/activity",      ACCESS_ADMIN, api_status_activity, NULL },
     { "connections/cancel",   ACCESS_ADMIN, api_connections_cancel, NULL },
     { NULL },
   };
index 13dc607431b497f8dbfb105244f5c702c27d7444..e07b681195e4d526d5f064e797ef45816ab372cc 100644 (file)
@@ -626,6 +626,8 @@ int dvr_entry_assign_broadcast(dvr_entry_t *de, epg_broadcast_t *bcast);
 
 dvr_entry_t *dvr_entry_find_by_id(int id);
 
+time_t dvr_entry_find_earliest(void);
+
 static inline dvr_entry_t *dvr_entry_find_by_uuid(const char *uuid)
   { return (dvr_entry_t*)idnode_find(uuid, &dvr_entry_class, NULL); }
 
index 4a64eb4bf9404048b64ba262dc2ad2f528f12fe8..431b820c23d9022c0073c435f765013c84b9a668 100644 (file)
@@ -3072,6 +3072,35 @@ dvr_entry_find_by_id(int id)
   return de;
 }
 
+/**
+ * Find the earliest scheduled dvr entry
+ */
+time_t
+dvr_entry_find_earliest(void)
+{
+  time_t start;
+  time_t earliest = 0;
+  dvr_entry_t *de;
+
+  LIST_FOREACH(de, &dvrentries, de_global_link)
+  {
+    if(dvr_entry_is_upcoming(de) && de->de_enabled)
+    {
+      start = dvr_entry_get_start_time(de, 1);
+      if(earliest == 0)
+      {
+        earliest = start;
+      }
+      else if(start < earliest)
+      {
+        earliest = start;
+      }
+    }
+  }//END FOREACH
+
+  return earliest;
+
+}
 
 /**
  * Unconditionally remove an entry
index 06073e981e095775658c20c9df383c241c3f3c73..20a1edddb845a18db320210e9fae492944f5e348 100644 (file)
@@ -509,6 +509,44 @@ const idclass_t epggrab_class = {
   }
 };
 
+/* **************************************************************************
+ * Get the time for the next scheduled internal grabber
+ * *************************************************************************/
+time_t epggrab_get_next_int(void)
+{
+  time_t ret_time;
+  struct timespec current_time;
+  
+  clock_gettime(CLOCK_REALTIME, &current_time);
+  if(!cron_multi_next(epggrab_cron_multi, current_time.tv_sec, &ret_time))
+  {
+    return ret_time;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+/* **************************************************************************
+ * Count the number of EPG grabbers of a specified type
+ * *************************************************************************/
+int epggrab_count_type(int grabberType)
+{
+  epggrab_module_t *mod;
+  int temp_count = 0;
+
+  LIST_FOREACH(mod, &epggrab_modules, link) {
+    if(mod->enabled && mod->type == grabberType)
+    {
+      temp_count++;
+    }
+  }
+
+  return temp_count;
+
+}
+
 /* **************************************************************************
  * Initialisation
  * *************************************************************************/
index 62020a49af8c6b1377a2c5912d243258a9d617c6..590df45dfbb4e37ffbb41cf75b9a9afbe884967b 100644 (file)
@@ -406,6 +406,16 @@ const char *epggrab_ota_check_module_id( const char *id );
  */
 extern unsigned char                *epggrab_ota_genre_translation;
 
+/*
+ * Get the next execution times
+ */
+time_t epggrab_get_next_int(void);
+time_t epggrab_get_next_ota(void);
+/*
+ * Count active grabbers for a given type
+ */
+int epggrab_count_type(int grabberType);
+
 #endif /* __EPGGRAB_H__ */
 
 /* **************************************************************************
index aa7d94c81bb794246ed0e3f39ae5d4c766c73cb1..0a5dc9345de42110f0d2ad01bd5b0bc02d5bd2c4 100644 (file)
@@ -1141,6 +1141,23 @@ epggrab_ota_set_genre_translation ( void )
   tvh_mutex_unlock(&epggrab_ota_mutex);
 }
 
+/* **************************************************************************
+ * Get the time for the next scheduled ota grabber
+ * *************************************************************************/
+time_t epggrab_get_next_ota(void)
+{
+  time_t ret_time = 0;
+  
+  if(!cron_multi_next(epggrab_ota_cron_multi, gclk(), &ret_time))
+  {
+    return ret_time;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
 /******************************************************************************
  * Editor Configuration
  *
index c7a1a4d4168a2b5404a7440e0df2525e57f2c376..1c30efc9fb90a9a7cd1865dc49d26f7003b34328 100644 (file)
@@ -383,6 +383,33 @@ mpegts_mux_sched_done ( void )
   tvh_mutex_unlock(&global_lock);
 }
 
+/*
+ * Earliest Mux scheduler
+ */
+time_t mpegts_mux_sched_next(void)
+{
+  time_t  earliest = 0;
+  mpegts_mux_sched_t *mms;
+
+  LIST_FOREACH(mms, &mpegts_mux_sched_all, mms_link)
+    {
+      if(mms->mms_enabled)  //Only process 'enabled' items.
+      {
+        if(!earliest)
+        {
+          earliest = mms->mms_start;
+        }
+        else if(mms->mms_start < earliest)
+        {
+          earliest = mms->mms_start;
+        }
+      }
+    }//END FOREACH
+
+  return earliest;
+
+}
+
 /******************************************************************************
  * Editor Configuration
  *
index b5e664f08c83949c913ddb46d82858b851fbb541..80c01b76265d170ec608a69cc072b1d5e2aec8ac 100644 (file)
@@ -72,6 +72,7 @@ void mpegts_mux_sched_delete ( mpegts_mux_sched_t *mms, int delconf );
 
 void mpegts_mux_sched_init ( void );
 void mpegts_mux_sched_done ( void );
+time_t mpegts_mux_sched_next(void);
 
 
 #endif /* __TVH_MPEGTS_H__ */
index 8ff5587301cfe57cd2815e3ba16df75def8f12de..0c86146a8e13e4c6704b7dd95252a2dc8a126221 100644 (file)
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -1156,6 +1156,23 @@ tcp_server_connections ( void )
   return m;
 }
 
+/*
+ * Connections count
+ */
+int
+tcp_server_connections_count ( void )
+{
+  tcp_server_launch_t *tsl;
+  int c = 0;
+  
+  /* Count connections */
+  LIST_FOREACH(tsl, &tcp_server_launches, link) {
+    if (!tsl->status) continue;
+    c++;
+  }
+
+  return c;
+}
 /**
  *
  */
index 5d32b892656a974df9cdc1b30886c103549e8d41..2ae9c1d39fc6497d12d6abc5f85062afdc450cc0 100644 (file)
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -164,5 +164,6 @@ void tcp_connection_cancel(uint32_t id);
 void tcp_connection_cancel_all(void);
 
 htsmsg_t *tcp_server_connections ( void );
+int tcp_server_connections_count ( void );
 
 #endif /* TCP_H_ */