From: pablozg Date: Tue, 19 Dec 2017 11:18:07 +0000 (+0100) Subject: DVR: add new features X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4a7962a2767fd1d108a5601342171e7cd7fdb697;p=thirdparty%2Ftvheadend.git DVR: add new features 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. --- diff --git a/src/api/api_dvr.c b/src/api/api_dvr.c index 8bf884cc8..80d9e7ec3 100644 --- a/src/api/api_dvr.c +++ b/src/api/api_dvr.c @@ -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 }, diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 69a4169a4..af87292c3 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -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); diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 9ddcd10b4..82d85d524 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -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); diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 7edc4110c..7a150e766 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -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) diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index 94cf7abea..109a85f28 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -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); diff --git a/src/webui/static/app/ext.css b/src/webui/static/app/ext.css index 894b735b9..0bab023c2 100644 --- a/src/webui/static/app/ext.css +++ b/src/webui/static/app/ext.css @@ -224,6 +224,14 @@ 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; }