]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
DVR: add new features
authorpablozg <pablozg@gmail.com>
Tue, 19 Dec 2017 11:18:07 +0000 (12:18 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 19 Dec 2017 15:53:08 +0000 (16:53 +0100)
Now the autorec name is by default the epg title.
A new button to show / hidde the skipped recordings in the webui.
A new button to add as completed an upcoming recording to avoid record it again.

src/api/api_dvr.c
src/dvr/dvr.h
src/dvr/dvr_autorec.c
src/dvr/dvr_db.c
src/webui/static/app/dvr.js
src/webui/static/app/ext.css

index 8bf884cc80e95ff5abb576fe9fce76e5cad80ede..80d9e7ec3c58d99c73c2bde1a6815f0030813503 100644 (file)
@@ -86,6 +86,17 @@ api_dvr_entry_grid_upcoming
       idnode_set_add(ins, (idnode_t*)de, &conf->filter, perm->aa_lang_ui);
 }
 
+static void
+api_dvr_entry_grid_duplicate
+  ( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
+{
+  dvr_entry_t *de;
+
+  LIST_FOREACH(de, &dvrentries, de_global_link)
+    if (dvr_entry_is_duplicate(de))
+      idnode_set_add(ins, (idnode_t*)de, &conf->filter, perm->aa_lang_ui);
+}
+
 static void
 api_dvr_entry_grid_finished
   ( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
@@ -334,6 +345,21 @@ api_dvr_entry_remove
   return api_idnode_handler(&dvr_entry_class, perm, args, resp, api_dvr_remove, "remove", 0);
 }
 
+static void
+api_dvr_previouslyrecorded(access_t *perm, idnode_t *self)
+{
+  dvr_entry_t *de = (dvr_entry_t *)self;
+  if (de->de_sched_state == DVR_SCHEDULED)
+    dvr_entry_previously_recorded(de);
+}
+
+static int
+api_dvr_entry_previouslyrecorded
+  ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+  return api_idnode_handler(&dvr_entry_class, perm, args, resp, api_dvr_previouslyrecorded, "remove", 0);
+}
+
 static void
 api_dvr_move_finished(access_t *perm, idnode_t *self)
 {
@@ -521,6 +547,7 @@ void api_dvr_init ( void )
     { "dvr/entry/class",           ACCESS_RECORDER, api_idnode_class, (void*)&dvr_entry_class },
     { "dvr/entry/grid",            ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid },
     { "dvr/entry/grid_upcoming",   ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_upcoming },
+    { "dvr/entry/grid_duplicate",  ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_duplicate },
     { "dvr/entry/grid_finished",   ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_finished },
     { "dvr/entry/grid_failed",     ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_failed },
     { "dvr/entry/grid_removed",    ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_removed },
@@ -531,6 +558,7 @@ void api_dvr_init ( void )
     { "dvr/entry/rerecord/allow",  ACCESS_RECORDER, api_dvr_entry_rerecord_allow, NULL },
     { "dvr/entry/stop",            ACCESS_RECORDER, api_dvr_entry_stop, NULL },   /* Stop active recording gracefully */
     { "dvr/entry/cancel",          ACCESS_RECORDER, api_dvr_entry_cancel, NULL }, /* Cancel scheduled or active recording */
+    { "dvr/entry/previouslyrecorded", ACCESS_RECORDER, api_dvr_entry_previouslyrecorded, NULL }, /* Add selected schedules as previously recorded */
     { "dvr/entry/remove",          ACCESS_RECORDER, api_dvr_entry_remove, NULL }, /* Remove recorded files from storage */
     { "dvr/entry/filemoved",       ACCESS_ADMIN,    api_dvr_entry_file_moved, NULL },
     { "dvr/entry/move/finished",   ACCESS_RECORDER, api_dvr_entry_move_finished, NULL },
index 69a4169a4435d1155bba5ea4bd3761c26c533498..af87292c352962d285ce902403dddcde7111ff81 100644 (file)
@@ -622,6 +622,8 @@ void dvr_entry_cancel_delete(dvr_entry_t *de, int rerecord);
 
 void dvr_entry_cancel_remove(dvr_entry_t *de, int rerecord);
 
+void dvr_entry_previously_recorded(dvr_entry_t *de);
+
 int dvr_entry_file_moved(const char *src, const char *dst);
 
 void dvr_entry_destroy(dvr_entry_t *de, int delconf);
@@ -634,6 +636,7 @@ htsmsg_t *dvr_entry_class_retention_list ( void *o, const char *lang );
 htsmsg_t *dvr_entry_class_removal_list ( void *o, const char *lang );
 
 int dvr_entry_is_upcoming(dvr_entry_t *entry);
+int dvr_entry_is_duplicate(dvr_entry_t *entry);
 int dvr_entry_is_finished(dvr_entry_t *entry, int flags);
 int dvr_entry_verify(dvr_entry_t *de, access_t *a, int readonly);
 
index 9ddcd10b44d386b9e0c9055265bc763609d1cf43..82d85d524c45fc47742c778394c128ff185bdc5c 100644 (file)
@@ -392,6 +392,7 @@ dvr_autorec_add_series_link(const char *dvr_config_name,
   htsmsg_t *conf;
   const char *chname;
   char *title;
+  const char *name;
   if (!event || !event->episode)
     return NULL;
   chname = channel_get_name(event->channel, NULL);
@@ -399,8 +400,10 @@ dvr_autorec_add_series_link(const char *dvr_config_name,
     return NULL;
   conf = htsmsg_create_map();
   title = regexp_escape(epg_broadcast_get_title(event, NULL));
+  name = epg_broadcast_get_title(event, NULL);
   htsmsg_add_u32(conf, "enabled", 1);
   htsmsg_add_str(conf, "title", title);
+  htsmsg_add_str(conf, "name", name);
   free(title);
   htsmsg_add_str(conf, "config_name", dvr_config_name ?: "");
   htsmsg_add_str(conf, "channel", chname);
index 7edc4110cafb09843683ab0223159ff4adc13f9d..7a150e766f661499b4dab5b99efb9ec118039070 100644 (file)
@@ -57,6 +57,8 @@ static void dvr_timer_stop_recording(void *aux);
 static int dvr_entry_rerecord(dvr_entry_t *de);
 static time_t dvr_entry_get_segment_stop_extra(dvr_entry_t *de);
 
+static dvr_entry_t *_dvr_duplicate_event(dvr_entry_t *de);
+
 /*
  *
  */
@@ -132,7 +134,15 @@ dvr_entry_trace_time2_(const char *file, int line,
 int dvr_entry_is_upcoming(dvr_entry_t *entry)
 {
   dvr_entry_sched_state_t state = entry->de_sched_state;
-  return state == DVR_RECORDING || state == DVR_SCHEDULED || state == DVR_NOSTATE;
+       return state == DVR_RECORDING || state == DVR_SCHEDULED || state == DVR_NOSTATE;
+}
+
+int dvr_entry_is_duplicate(dvr_entry_t *entry)
+{
+       dvr_entry_sched_state_t state = entry->de_sched_state;
+       if (_dvr_duplicate_event(entry) == 0){
+               return state == DVR_RECORDING || state == DVR_SCHEDULED || state == DVR_NOSTATE;
+       }else return 0;
 }
 
 int dvr_entry_is_finished(dvr_entry_t *entry, int flags)
@@ -4193,6 +4203,35 @@ dvr_entry_cancel(dvr_entry_t *de, int rerecord)
   return de;
 }
 
+static void
+dvr_entry_add_previously_recorded(dvr_entry_t *de)
+{
+       de->de_dont_reschedule = 1; // Set as not reschedule
+       de->de_file_removed = 1; // Set as file removed
+       de->de_start = gclk(); // Need in case you want to record it again after.
+       de->de_stop = gclk() + 1000;
+       dvr_entry_completed(de, SM_CODE_OK); // mark as completed
+       idnode_changed(&de->de_id);
+
+       dvr_entry_retention_timer(de);
+
+       htsp_dvr_entry_update(de);
+       idnode_notify_changed(&de->de_id);
+
+       tvhinfo(LS_DVR, "\"%s\" on \"%s\": "
+                       "set as previously recorded",
+                       lang_str_get(de->de_title, NULL), DVR_CH_NAME(de));
+}
+
+/**
+ * Add a schedule as previously recorded
+ */
+void
+dvr_entry_previously_recorded(dvr_entry_t *de)
+{
+  dvr_entry_add_previously_recorded(de);
+}
+
 /**
  * Called by 'dvr_entry_cancel_remove' and 'dvr_entry_cancel_delete'
  * delete = 0 -> remove finished and active recordings (visible as removed)
index 94cf7abea7e0473960494b63070d1779fcd4e859..109a85f2816bf1a7165080e35813f9d4359b93b0 100644 (file)
@@ -330,6 +330,59 @@ tvheadend.dvr_upcoming = function(panel, index) {
         }
     };
 
+    var previouslyrecordedButton = {
+        name: 'previouslyrecorded',
+        builder: function() {
+            return new Ext.Toolbar.Button({
+                tooltip: _('Add as recorded the selected program'),
+                iconCls: 'previouslyrecorded',
+                text: _('Add as recorded'),
+                disabled: true
+            });
+        },
+        callback: function(conf, e, store, select) {
+            var r = select.getSelections();
+            if (r && r.length > 0) {
+                var uuids = [];
+                for (var i = 0; i < r.length; i++)
+                    uuids.push(r[i].id);
+                tvheadend.AjaxConfirm({
+                    url: 'api/dvr/entry/previouslyrecorded',
+                    params: {
+                        uuid: Ext.encode(uuids)
+                    },
+                    success: function(d) {
+                        store.reload();
+                    },
+                                                                               question: _('Do you really want to add the selected recordings as previosly recorded?')
+                });
+            }
+        }
+    };
+
+               var showSkippedButton = {
+                               name: 'showskipped',
+                               builder: function() {
+                                               return new Ext.Toolbar.Button({
+                                                               tooltip: _('Show / hide skipped recordings'),
+                                                               iconCls: 'showskipped',
+                                                               text: _('View skipped recordings'),
+                                                               disabled: false,
+                                                               pressed: false,
+                                                               enableToggle: true
+                                               });
+                               },
+                               callback: function(conf, e, store) {
+                                               if (store.proxy.url === 'api/dvr/entry/grid_duplicate'){
+                                                       store.proxy.setUrl('api/dvr/entry/grid_upcoming',true);
+                                                       store.load();
+                                               }else{
+                                                       store.proxy.setUrl('api/dvr/entry/grid_duplicate',true);
+                                                       store.load();
+                                       }
+                               }
+               };
+
     function selected(s, abuttons) {
         var recording = 0;
         s.each(function(s) {
@@ -338,6 +391,7 @@ tvheadend.dvr_upcoming = function(panel, index) {
         });
         abuttons.stop.setDisabled(recording < 1);
         abuttons.abort.setDisabled(recording < 1);
+        abuttons.previouslyrecorded.setDisabled(recording >= 1);
     }
 
     function beforeedit(e, grid) {
@@ -347,7 +401,7 @@ tvheadend.dvr_upcoming = function(panel, index) {
 
     tvheadend.idnode_grid(panel, {
         url: 'api/dvr/entry',
-        gridURL: 'api/dvr/entry/grid_upcoming',
+        gridURL: 'api/dvr/entry/grid_duplicate',
         titleS: _('Upcoming Recording'),
         titleP: _('Upcoming / Current Recordings'),
         iconCls: 'upcomingRec',
@@ -404,7 +458,7 @@ tvheadend.dvr_upcoming = function(panel, index) {
             actions,
             tvheadend.contentTypeAction,
         ],
-        tbar: [stopButton, abortButton],
+        tbar: [stopButton, abortButton, previouslyrecordedButton, showSkippedButton],
         selected: selected,
         beforeedit: beforeedit
     });
@@ -759,7 +813,7 @@ tvheadend.dvr_removed = function(panel, index) {
             }
         }
     };
-    
+
     function selected(s, abuttons) {
         var r = s.getSelections();
         abuttons.rerecord.setDisabled(r.length <= 0);
index 894b735b9654ad6d632820a46e6973255231257d..0bab023c2ee8271f158e16f37685603c540039c8 100644 (file)
     background-image: url(../icons/delete.png) !important;
 }
 
+.previouslyrecorded {
+    background-image: url(../icons/accept.png) !important;
+}
+
+.showskipped {
+    background-image: url(../icons/other_filters.png) !important;
+}
+
 .cancel {
     background-image: url(../icons/cancel.png) !important;
 }