]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
ui: Allow filtering/autorec from EPG by category. (#4777).
authorE.Smith <31170571+azlm8t@users.noreply.github.com>
Tue, 5 Dec 2017 20:11:10 +0000 (20:11 +0000)
committerJaroslav Kysela <perex@perex.cz>
Sun, 10 Dec 2017 15:40:50 +0000 (16:40 +0100)
If we have categories on the server (from xmltv) then
we create a second toolbar on the EPG and add filters for
filtering by category. These are then included in the
autorec rule created from the EPG.

We use a second toolbar since the primary toolbar is a
too cramped to fit more search drop-down boxes.

Issue: #4777.

src/api/api_epg.c
src/dvr/dvr_db.c
src/epg.c
src/epg.h
src/webui/static/app/epg.js

index 94b4a52acc656650e0f407899f7cbaef665c932f..60847c5d7b7e0fad65a5ee12af1bd1ad1c344222 100644 (file)
@@ -349,6 +349,15 @@ api_epg_grid
   str = htsmsg_get_str(args, "channelTag");
   if (str)
     eq.channel_tag = strdup(str);
+  str = htsmsg_get_str(args, "cat1");
+  if (str)
+    eq.cat1 = strdup(str);
+  str = htsmsg_get_str(args, "cat2");
+  if (str)
+    eq.cat2 = strdup(str);
+  str = htsmsg_get_str(args, "cat3");
+  if (str)
+    eq.cat3 = strdup(str);
 
   if (mode != NULL) {
       if (!strcmp(mode, "now")) {
index f548a4ca7333f290ca631a4a1b1fc8029dec75a7..f60563e18a59ad6d400dd156e8a6904eb4973afb 100644 (file)
@@ -1024,6 +1024,12 @@ dvr_entry_create_(int enabled, const char *config_uuid, epg_broadcast_t *e,
   {
     htsmsg_add_str(conf, "autorec", idnode_uuid_as_str(&dae->dae_id, ubuf));
     htsmsg_add_str(conf, "directory", dae->dae_directory ?: "");
+    if (dae->dae_cat1 && *dae->dae_cat1)
+      htsmsg_add_str(conf, "cat1", dae->dae_cat1);
+    if (dae->dae_cat2 && *dae->dae_cat2)
+      htsmsg_add_str(conf, "cat2", dae->dae_cat2);
+    if (dae->dae_cat3 && *dae->dae_cat3)
+      htsmsg_add_str(conf, "cat3", dae->dae_cat3);
   }
   if (dte)
   {
index 01a5589bf8e98b5247f760a5b006f023ec07adf4..9977f5784b6400f6c6b31d6e1f8e87bb0f3e2112 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -2917,6 +2917,28 @@ _eq_add ( epg_query_t *eq, epg_broadcast_t *e )
     if (_eq_comp_num(&eq->channel_num, channel_get_number(e->channel))) return;
   if (eq->channel_name.comp != EC_NO)
     if (_eq_comp_str(&eq->channel_name, channel_get_name(e->channel, NULL))) return;
+  if (eq->cat1 && *eq->cat1) {
+      /* No category? Can't match our requested category */
+      if (!e->category)
+          return;
+      if (!string_list_contains_string(e->category, eq->cat1))
+          return;
+  }
+  if (eq->cat2 && *eq->cat2) {
+      /* No category? Can't match our requested category */
+      if (!e->category)
+          return;
+      if (!string_list_contains_string(e->category, eq->cat2))
+          return;
+  }
+  if (eq->cat3 && *eq->cat3) {
+      /* No category? Can't match our requested category */
+      if (!e->category)
+          return;
+      if (!string_list_contains_string(e->category, eq->cat3))
+          return;
+  }
+
   if (eq->genre_count) {
     epg_genre_t genre;
     uint32_t i, r = 0;
@@ -3277,6 +3299,10 @@ fin:
   free(eq->channel); eq->channel = NULL;
   free(eq->channel_tag); eq->channel_tag = NULL;
   free(eq->stitle); eq->stitle = NULL;
+  free(eq->cat1); eq->cat1 = NULL;
+  free(eq->cat2); eq->cat2 = NULL;
+  free(eq->cat3); eq->cat3 = NULL;
+
   if (eq->genre != eq->genre_static)
     free(eq->genre);
   eq->genre = NULL;
index c1d5aa8620143db81097ccc77dda52c0303624bf..7ce6a4205ff54c94cdcf8adcccc767b66d27419c 100644 (file)
--- a/src/epg.h
+++ b/src/epg.h
@@ -697,6 +697,9 @@ typedef struct epg_query {
   uint32_t          genre_count;
   uint8_t          *genre;
   uint8_t           genre_static[16];
+  char             *cat1;
+  char             *cat2;
+  char             *cat3;
 
   enum {
     ESK_START,
index 68085e261dad4d91abaeebfd4dea3ff2e5aee72c..76ba7ee01418111d76575a8351884864e06a649d 100644 (file)
@@ -10,6 +10,27 @@ tvheadend.ContentGroupStore = tvheadend.idnode_get_enum({
     }
 });
 
+insertCategoryClearOption = function( scope, records, options ){
+    var placeholder = Ext.data.Record.create(['key', 'val']);
+    scope.insert(0,new placeholder({key: '-1', val: _('(Clear filter)')}));
+};
+
+tvheadend.category = tvheadend.idnode_get_enum({
+    url: 'api/channelcategory/list',
+    event: 'channelcategory',
+    listeners: {
+        'load': function(scope, records, options) {
+          insertCategoryClearOption(scope, records, options);
+          // If we have categories then we create the category
+          // search toolbar.
+          if (records.length) {
+            tvheadend.createToolbar2();
+          }
+        }
+    }
+});
+
+
 tvheadend.contentGroupLookupName = function(code) {
     ret = "";
     if (!code)
@@ -774,6 +795,59 @@ tvheadend.epg = function() {
 
     });
 
+    /// "cat" is the name of the category field.
+    /// We have to pass the name, not the field, since the
+    /// field is deleted and re-created inside clear filter.
+    function createFilterCat(clearFilter, cat) {
+      var filter = new Ext.form.ComboBox({
+        loadingText: _('Loading...'),
+        width: 200,
+        displayField: 'val',
+        store: tvheadend.category,
+        mode: 'local',
+        editable: true,
+        forceSelection: true,
+        triggerAction: 'all',
+        typeAhead: true,
+        emptyText: _('Filter category...'),
+        listeners: {
+            blur: function () {
+                if(this.getRawValue() == "" ) {
+                    clearFilter();
+                    epgView.reset();
+                }
+            }
+        }
+      });
+      filter.on('select', function(c, r) {
+        if (r.data.key == -1)
+            clearFilter();
+        else if (epgStore.baseParams[cat] !== r.data.key)
+            epgStore.baseParams[cat] = r.data.key;
+        epgView.reset();
+      });
+      return filter;
+    }
+
+    clearCat1Filter = function() {
+        delete epgStore.baseParams.cat1;
+        epgFilterCat1.setValue("");
+    }
+
+    clearCat2Filter = function() {
+        delete epgStore.baseParams.cat2;
+        epgFilterCat2.setValue("");
+    }
+
+    clearCat3Filter = function() {
+        delete epgStore.baseParams.cat3;
+        epgFilterCat3.setValue("");
+    }
+
+    var epgFilterCat1 = createFilterCat(clearCat1Filter, "cat1");
+    var epgFilterCat2 = createFilterCat(clearCat2Filter, "cat2");
+    var epgFilterCat3 = createFilterCat(clearCat3Filter, "cat3");
+
     // Content groups
 
     var epgFilterContentGroup = new Ext.form.ComboBox({
@@ -867,6 +941,9 @@ tvheadend.epg = function() {
         clearChannelTagsFilter();
         clearDurationFilter();
         clearContentGroupFilter();
+        clearCat1Filter();
+        clearCat2Filter();
+        clearCat3Filter();
         filter.clearFilters();
         delete epgStore.sortInfo;
         epgView.reset();
@@ -1043,6 +1120,18 @@ tvheadend.epg = function() {
         epgView.reset();
     });
 
+    /* Extra toolbar. Only created if we have categories on the server */
+    tvheadend.createToolbar2 = function() {
+        var tbar2 = new Ext.Toolbar({
+          items: [
+              epgFilterCat1, '-',
+              epgFilterCat2, '-',
+              epgFilterCat3, '-',
+          ]
+        });
+        panel.add(tbar2);
+    }
+
     /**
      * Listener for EPG and DVR notifications.
      * We want to update the EPG grid when a recording is finished/deleted etc.
@@ -1155,6 +1244,12 @@ tvheadend.epg = function() {
         var duration = epgStore.baseParams.durationMin ?
                 tvheadend.durationLookupRange(epgStore.baseParams.durationMin)
                 : "<i>" + _("Don't care") + "</i>";
+        var cat1 = epgStore.baseParams.cat1 ?
+                '<div class="x-smallhdr">' + _('Category') + ':</div>' + epgStore.baseParams.cat1 + '<br>' : "";
+        var cat2 = epgStore.baseParams.cat2 ?
+                '<div class="x-smallhdr">' + _('Category') + ':</div>' + epgStore.baseParams.cat2 + '<br>' : "";
+        var cat3 = epgStore.baseParams.cat3 ?
+                '<div class="x-smallhdr">' + _('Category') + ':</div>' + epgStore.baseParams.cat3 + '<br>' : "";
 
         Ext.MessageBox.confirm(_('Auto Recorder'), _('This will create an automatic rule that '
                 + 'continuously scans the EPG for programs '
@@ -1164,6 +1259,7 @@ tvheadend.epg = function() {
                 + '<div class="x-smallhdr">' + _('Tag') + ':</div>' + tag + '<br>'
                 + '<div class="x-smallhdr">' + _('Genre') + ':</div>' + contentType + '<br>'
                 + '<div class="x-smallhdr">' + _('Duration') + ':</div>' + duration + '<br>'
+                + cat1 + cat2 + cat3
                 + '<br><br>'
                 + sprintf(_('Currently this will match (and record) %d events.'), epgStore.getTotalCount())
                 + ' ' + 'Are you sure?',
@@ -1187,6 +1283,9 @@ tvheadend.epg = function() {
         if (params.contentType) conf.content_type = params.contentType;
         if (params.durationMin) conf.minduration = params.durationMin;
         if (params.durationMax) conf.maxduration = params.durationMax;
+        if (params.cat1) conf.cat1 = params.cat1;
+        if (params.cat2) conf.cat2 = params.cat2;
+        if (params.cat3) conf.cat3 = params.cat3;
         Ext.Ajax.request({
             url: 'api/dvr/autorec/create',
             params: { conf: Ext.encode(conf) }