]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
eit: Extract season/episode numbers from OTA EIT. (#4287).
authorE.Smith <31170571+azlm8t@users.noreply.github.com>
Tue, 5 Sep 2017 11:43:19 +0000 (12:43 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 8 Sep 2017 06:29:45 +0000 (08:29 +0200)
Broadcasters often include season and episode number in
the summary text in the OTA EIT.

For example, UK broadcasters often, but not always,
have a description of "Lorem ipsum (S5 Ep 8)" or
"Lorem ipsum (S3 Ep 4/9)" or "Lorem ipsum (Ep 4)".

From this we can use a regular expression match to
extract the season and episode data on a best effort
basis. This logic is based on the opentv extractor.

This is done via config files that are named after the
grabber module and exist in this directory:
data/conf/epggrab/eit/fixup/
Example names would be uk_freeview.

If the module-specific config file does not exist then we
fallback to trying the first component of the filename.

In the above example that would be "uk". This avoids having
duplicate files in the case where we have DVB-S and DVB-T
in the same country that share the same extraction regex.

The configuration file should contain season_num and
episode_num sections that can contain multiple regular
expressions to apply in sequence until one produces
a match.

For DVB-S, the configuration file normally needs to be copied to
a file named "eit" since data is broadcast via that mechanism.
This isn't done by default since the eit grabber is used by
multiple countries that may use different regular expressions.

Issue: #4287

data/conf/epggrab/eit/fixup/uk [new file with mode: 0644]
src/epggrab/module/eit.c

diff --git a/data/conf/epggrab/eit/fixup/uk b/data/conf/epggrab/eit/fixup/uk
new file mode 100644 (file)
index 0000000..b149472
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "season_num": [
+    " *\\(S ?([0-9]+),? [Ee]p? ?[0-9]+\\)",
+    " *\\(S ?([0-9]+),? [Ee]p? ?[0-9]+/[0-9]+\\)",
+    " S ?([0-9]+)[ /][Ee]p? ?[0-9]+",
+    "^S ?([0-9]+),? [Ee]p? ?[0-9]+\\\."
+  ],
+  "episode_num": [
+    " *\\(S ?[0-9]+,? [Ee]p? ?([0-9]+)\\)",
+    " *\\(S ?[0-9]+,? [Ee]p? ?([0-9]+)/[0-9]+\\)",
+    " S ?[0-9]+[ /][Ee]p? ?([0-9]+)",
+    "^S ?[0-9]+,? [Ee]p? ?([0-9]+)\\\.",
+    " *\\([Ee]p ?([0-9]+)\\)",
+    " *\\([Ee]p ?([0-9]+)/[0-9]+\\)",
+    "^([0-9]+)/[0-9]+\. "
+  ]
+}
index e41aaba1d8688ffd4e82d0349b4f6820e9f4f402..8fc8fafe709d754173ebab2533c4028d64273ea1 100644 (file)
@@ -24,6 +24,7 @@
 #include "epg.h"
 #include "epggrab.h"
 #include "epggrab/private.h"
+#include "eitpatternlist.h"
 #include "input.h"
 #include "input/mpegts/dvb_charset.h"
 #include "dvr/dvr.h"
@@ -44,6 +45,15 @@ typedef struct eit_private
 #define EIT_SPEC_UK_FREESAT  1
 #define EIT_SPEC_NZ_FREEVIEW 2
 
+
+/* Provider configuration */
+typedef struct eit_module_t
+{
+  epggrab_module_ota_t  ;      ///< Base struct
+  eit_pattern_list_t p_snum;
+  eit_pattern_list_t p_enum;
+} eit_module_t;
+
 /* ************************************************************************
  * Status handling
  * ***********************************************************************/
@@ -421,6 +431,7 @@ static int _eit_process_event_one
     const uint8_t *ptr, int len,
     int local, int *resched, int *save )
 {
+  eit_module_t* eit_mod = (eit_module_t*)mod;
   int dllen, save2 = 0, rsonly = 0;
   time_t start, stop;
   uint16_t eid;
@@ -580,6 +591,22 @@ static int _eit_process_event_one
     ee = epg_episode_find_by_broadcast(ebc, mod, 1, save, &changes4);
   }
 
+  epg_episode_num_t en;
+  memset(&en, 0, sizeof(en));
+
+  if (ev.summary) {
+    /* search for season number */
+    char buffer[2048];
+    const char* summary = lang_str_get(ev.summary, ev.default_charset);
+    if (eit_pattern_apply_list(buffer, sizeof(buffer), summary, &eit_mod->p_snum))
+      if ((en.s_num = atoi(buffer)))
+        tvhtrace(LS_TBL_EIT,"  extract season number %d using %s", en.s_num, mod->id);
+    /* ...for episode number */
+    if (eit_pattern_apply_list(buffer, sizeof(buffer), summary, &eit_mod->p_enum))
+      if ((en.e_num = atoi(buffer)))
+        tvhtrace(LS_TBL_EIT,"  extract episode number %d using %s", en.e_num, mod->id);
+  }
+
   /* Update Episode */
   if (ee) {
     *save |= epg_broadcast_set_episode(ebc, ee, &changes2);
@@ -596,6 +623,9 @@ static int _eit_process_event_one
     if (ev.extra)
       *save |= epg_episode_set_extra(ee, extra, &changes4);
 #endif
+    /* save any found episode number */
+    if (en.s_num || en.e_num || en.p_num)
+      *save |= epg_episode_set_epnum(ee, &en, &changes4);
     *save |= epg_episode_change_finish(ee, changes4, 0);
   }
 
@@ -899,6 +929,66 @@ static int _eit_tune
   return r;
 }
 
+static int _eit_fixup_load_one ( htsmsg_t *m, eit_module_t* mod )
+{
+    eit_pattern_compile_list(&mod->p_snum, htsmsg_get_list(m, "season_num"));
+    eit_pattern_compile_list(&mod->p_enum, htsmsg_get_list(m, "episode_num"));
+    return 1;
+}
+
+static eit_module_t *eit_module_ota_create
+  ( const char *id, int subsys, const char *saveid,
+    const char *name, int priority,
+    epggrab_ota_module_ops_t *ops )
+{
+  eit_module_t * mod = (eit_module_t *)
+    epggrab_module_ota_create(calloc(1, sizeof(eit_module_t)),
+                              id, subsys, saveid,
+                              name, priority, ops);
+
+  const char config_path[] = "epggrab/eit/fixup/%s";
+  const char *config_file = id;
+
+  /* Attempt to load config file based on grabber id such as
+   * uk_freeview.
+   */
+  htsmsg_t *m = hts_settings_load(config_path, config_file);
+  char *generic_name = NULL;
+  if (!m) {
+    /* No config file so try loading a generic config based on
+     * the first component of the id. In the above case it would
+     * be "uk". This allows config for a country to be shared across
+     * two grabbers such as DVB-T and DVB-S.
+     */
+    generic_name = strdup(id);
+    if (generic_name) {
+      char *underscore = strstr(generic_name, "_");
+      if (underscore) {
+        /* Terminate the string at the underscore */
+        *underscore = 0;
+        config_file = generic_name;
+        m = hts_settings_load(config_path, config_file);
+      }
+    }
+  }
+
+  if (m) {
+    const int r = _eit_fixup_load_one(m, mod);
+    if (r > 0)
+      tvhinfo(LS_TBL_EIT, "fixup %s loaded %s", id, config_file);
+    else
+      tvhwarn(LS_TBL_EIT, "fixup %s failed", id);
+    htsmsg_destroy(m);
+  } else {
+      tvhinfo(LS_TBL_EIT, "no fixup config files loaded for %s", id);
+  }
+
+  if (generic_name)
+    free(generic_name);
+
+  return mod;
+}
+
 #define EIT_OPS(name, _pid, _conv, _spec) \
   static eit_private_t opaque_##name = { \
     .pid = (_pid), \
@@ -912,7 +1002,7 @@ static int _eit_tune
   }
 
 #define EIT_CREATE(id, name, prio, ops) \
-  epggrab_module_ota_create(NULL, id, LS_TBL_EIT, NULL, name, prio, ops)
+  eit_module_ota_create(id, LS_TBL_EIT, NULL, name, prio, ops)
 
 void eit_init ( void )
 {