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