From: DeltaMikeCharlie <127641886+DeltaMikeCharlie@users.noreply.github.com>
Date: Sat, 22 Jul 2023 22:13:07 +0000 (+1000)
Subject: OTA Genre translation squashed v2
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=23263a54d9bbda2779489c06d3aa909ec618ad63;p=thirdparty%2Ftvheadend.git
OTA Genre translation squashed v2
---
diff --git a/docs/property/ota_genre_translation.md b/docs/property/ota_genre_translation.md
new file mode 100644
index 000000000..f6165d02d
--- /dev/null
+++ b/docs/property/ota_genre_translation.md
@@ -0,0 +1,21 @@
+
+
+Use this setting to translate broadcaster-specific, country-specific or other customised genre tags into tags recognised by tvheadend.
+
+Example:
+
+```
+192=20
+208=16
+224=35
+```
+
+| Line | Meaning |
+| ------------- | ------------- |
+|192=20|Translate decimal 192 (0xC0 = Australian-specific 'comedy') to decimal 20 (0x14 = ETSI standard 'comedy').|
+|208=16|Translate decimal 208 (0xD0 = Australian-specific 'drama') to decimal 16 (0x10 = ETSI standard 'movie/drama (general)').|
+|224=35|Translate decimal 224 (0xE0 = Australian-specific 'documentary') to decimal 35 (0x23 = ETSI standard 'documentary').|
+
+See: [Search the ETSI web site for the latest version of the 'ETSI EN 300 468' standard.](https://www.etsi.org/standards#page=1&search=%22ETSI%20EN%20300%20468%22&title=0&etsiNumber=1&content=0&version=1&onApproval=1&published=1&withdrawn=1&historical=1&isCurrent=1&superseded=1&startDate=1988-01-15&endDate=2023-07-09&harmonized=0&keyword=&TB=&stdType=&frequency=&mandate=&collection=&sort=1)
+
+Search for 'content_descriptor' in the standards document.
\ No newline at end of file
diff --git a/src/epggrab.c b/src/epggrab.c
index 6e419f071..415250061 100644
--- a/src/epggrab.c
+++ b/src/epggrab.c
@@ -328,8 +328,15 @@ epggrab_class_ota_cron_notify(void *self, const char *lang)
epggrab_ota_set_cron();
}
+static void
+epggrab_class_ota_genre_translation_notify(void *self, const char *lang)
+{
+ epggrab_ota_set_genre_translation();
+}
+
CLASS_DOC(epgconf)
PROP_DOC(cron)
+PROP_DOC(ota_genre_translation)
const idclass_t epggrab_class = {
.ic_snode = &epggrab_conf.idnode,
@@ -353,7 +360,11 @@ const idclass_t epggrab_class = {
.name = N_("OTA (Over-the-air) Grabber Settings"),
.number = 3,
},
- {}
+ {
+ .name = N_("OTA (Over-the-air) Genre Translation"),
+ .number = 4,
+ },
+ {}
},
.ic_properties = (const property_t[]){
{
@@ -471,6 +482,21 @@ const idclass_t epggrab_class = {
.opts = PO_EXPERT,
.group = 3,
},
+ {
+ .type = PT_STR,
+ .id = "ota_genre_translation",
+ .name = N_("Over-the-air Genre Translation"),
+ .desc = N_("Translate the genre codes received from the broadcaster to another genre code."
+ "
Use the form xxx=yyy, where xxx and yyy are "
+ "'ETSI EN 300 468' content descriptor values expressed in decimal (0-255). "
+ "
Genre code xxx will be converted to genre code yyy."
+ "
Use a separate line for each genre code to be converted."),
+ .doc = prop_doc_ota_genre_translation,
+ .off = offsetof(epggrab_conf_t, ota_genre_translation),
+ .notify = epggrab_class_ota_genre_translation_notify,
+ .opts = PO_MULTILINE | PO_EXPERT,
+ .group = 4,
+ },
{}
}
};
diff --git a/src/epggrab.h b/src/epggrab.h
index b8f2798ce..90346fdca 100644
--- a/src/epggrab.h
+++ b/src/epggrab.h
@@ -319,6 +319,7 @@ typedef struct epggrab_conf {
uint32_t epgdb_periodicsave;
uint32_t epgdb_saveafterimport;
char *ota_cron;
+ char *ota_genre_translation;
uint32_t ota_timeout;
uint32_t ota_initial;
uint32_t int_initial;
@@ -365,10 +366,11 @@ extern int epggrab_ota_running;
/*
* Set configuration
*/
-int epggrab_activate_module ( epggrab_module_t *mod, int activate );
-void epggrab_ota_set_cron ( void );
-void epggrab_ota_trigger ( int secs );
-void epggrab_rerun_internal ( void );
+int epggrab_activate_module ( epggrab_module_t *mod, int activate );
+void epggrab_ota_set_cron ( void );
+void epggrab_ota_set_genre_translation ( void );
+void epggrab_ota_trigger ( int secs );
+void epggrab_rerun_internal ( void );
/*
* Load/Save
@@ -398,6 +400,11 @@ epggrab_ota_mux_t *epggrab_ota_find_mux ( struct mpegts_mux *mm );
htsmsg_t *epggrab_ota_module_id_list( const char *lang );
const char *epggrab_ota_check_module_id( const char *id );
+/*
+ * Global variable for genre translation
+ */
+extern unsigned char epggrab_ota_genre_translation[256];
+
#endif /* __EPGGRAB_H__ */
/* **************************************************************************
diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c
index 8b938f5d5..4ae2b126f 100644
--- a/src/epggrab/module/eit.c
+++ b/src/epggrab/module/eit.c
@@ -391,12 +391,21 @@ static int _eit_desc_component
static int _eit_desc_content
( epggrab_module_t *mod, const uint8_t *ptr, int len, eit_event_t *ev )
{
+ uint8_t tempPtr = 0; //Temporary variable to hold a (potentially) changed *ptr value.
+ tempPtr = *ptr;
while (len > 1) {
- if (*ptr == 0xb1)
+ //Get the potentially new genre value.
+ tempPtr = epggrab_ota_genre_translation[*ptr];
+ //If we did get a translation, write a trace for debugging.
+ if(tempPtr != *ptr)
+ {
+ tvhtrace(LS_TBL_EIT, "Translating '%d' to '%d'", *ptr, tempPtr);
+ }
+ if (tempPtr == 0xb1) //0xB1 is the genre code for 'Black and White'
ev->bw = 1;
- else if (*ptr < 0xb0) {
+ else if (tempPtr < 0xb0) { //0xB0 is the start of the 'Special Characteristics' block.
if (!ev->genre) ev->genre = calloc(1, sizeof(epg_genre_list_t));
- epg_genre_list_add_by_eit(ev->genre, *ptr);
+ epg_genre_list_add_by_eit(ev->genre, (const uint8_t)tempPtr); //Cast as a 'const'
}
len -= 2;
ptr += 2;
diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c
index 4888158ba..c55b126cd 100644
--- a/src/epggrab/otamux.c
+++ b/src/epggrab/otamux.c
@@ -56,6 +56,8 @@ int epggrab_ota_pending_flag;
tvh_mutex_t epggrab_ota_mutex;
+unsigned char epggrab_ota_genre_translation[256];
+
SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t);
SKEL_DECLARE(epggrab_svc_link_skel, epggrab_ota_svc_link_t);
@@ -1035,6 +1037,92 @@ epggrab_ota_set_cron ( void )
epggrab_ota_arm((time_t)-1);
}
+void
+epggrab_ota_set_genre_translation ( void )
+{
+
+ tvhtrace(LS_EPGGRAB, "Processing genre code translations.");
+
+ //Take the raw setting data and parse it into the genre translation table.
+ //There is some sanity checking done, however, the data is entered as freeform
+ //text by the user and errors may still slip through.
+ //Note: Each line that comes back from the WebUI is separated by a LF (0x0A).
+ //^^^^ This has been tested with a Windows WebUI client and it only sends LF, not CR/LF.
+
+ lock_assert(&global_lock);
+ tvh_mutex_lock(&epggrab_ota_mutex);
+
+ //Reset the translation table to 1:1 here before proceeding.
+ for(int i = 0; i < 256; i++)
+ {
+ epggrab_ota_genre_translation[i] = i;
+ }
+
+ int tempPos = 0;
+ int outPos = 0;
+ int tempLen = 0;
+ char *tempPair = NULL;
+ int tempFrom = -1;
+ int tempTo = -1;
+ tempLen = strlen(epggrab_conf.ota_genre_translation);
+
+ //Make sure that this is large enough to take the whole config string in one go
+ //to allow for it being full of nonsense entered by the user.
+ tempPair = calloc(tempLen + 1, 1);
+
+ //Read through the user input byte by byte and parse out the lines
+ for(tempPos = 0; tempPos < tempLen; tempPos++)
+ {
+ //If the current character is not a new line or a comma. (Comma is an undocumented courtesy!)
+ if(epggrab_conf.ota_genre_translation[tempPos] != 10 && epggrab_conf.ota_genre_translation[tempPos] != ',')
+ {
+ //Only allow numerals, '=' and '#' to pass through.
+ //ASCII 0-9 = 48-57, '=' = 61 (in decimal)
+ if((epggrab_conf.ota_genre_translation[tempPos] >= 48 && epggrab_conf.ota_genre_translation[tempPos] <= 57) || epggrab_conf.ota_genre_translation[tempPos] == 61 || epggrab_conf.ota_genre_translation[tempPos] == '#')
+ {
+ tempPair[outPos] = epggrab_conf.ota_genre_translation[tempPos];
+ tempPair[outPos + 1] = 0;
+ outPos++;
+ }
+ }
+
+ //If we have a new line or a comma or we are at the end of the config string
+ if(epggrab_conf.ota_genre_translation[tempPos] == 10 || epggrab_conf.ota_genre_translation[tempPos] == ',' || tempPos == (tempLen - 1))
+ {
+ //Only process non-null strings.
+ if(strlen(tempPair) != 0)
+ {
+ tempFrom = -1;
+ tempTo = -1;
+ sscanf(tempPair, "%d=%d", &tempFrom, &tempTo);
+ //Test that the to/from values are sane before proceeding.
+ if(tempFrom > -1 && tempFrom < 256 && tempTo > -1 && tempTo < 256)
+ {
+ tvhtrace(LS_EPGGRAB, "Valid translation from '%d' to '%d'.", tempFrom, tempTo);
+ epggrab_ota_genre_translation[tempFrom] = tempTo;
+ }
+ else
+ {
+ tvhtrace(LS_EPGGRAB, "Ignoring '%s'.", tempPair);
+ }
+ outPos = 0;
+ tempPair[0] = 0;
+ }
+ }
+ }
+
+ for(int x = 0; x < 256; x++)
+ {
+ if(epggrab_ota_genre_translation[x] != x)
+ {
+ tvhtrace(LS_EPGGRAB, "Genre '%d' (0x%02x) translates to genre '%d' (0x%02x).", x, x, epggrab_ota_genre_translation[x], epggrab_ota_genre_translation[x]);
+ }
+ }
+ free(tempPair);
+
+ tvh_mutex_unlock(&epggrab_ota_mutex);
+}
+
/******************************************************************************
* Editor Configuration
*
diff --git a/src/webui/static/img/doc/channel/epgconf_tab.png b/src/webui/static/img/doc/channel/epgconf_tab.png
old mode 100644
new mode 100755
index dc5e111e8..be4db94b4
Binary files a/src/webui/static/img/doc/channel/epgconf_tab.png and b/src/webui/static/img/doc/channel/epgconf_tab.png differ