From: Glenn-1990 Date: Fri, 4 Nov 2016 14:25:38 +0000 (+0100) Subject: Implement playcount and playposition X-Git-Tag: v4.2.1~207 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=790b38ce7df0121f219161f56dad02f5086f6f65;p=thirdparty%2Ftvheadend.git Implement playcount and playposition --- diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 054dcd129..bd324b6de 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -209,6 +209,8 @@ typedef struct dvr_entry { uint32_t de_file_removed; uint32_t de_retention; uint32_t de_removal; + uint32_t de_playcount; /* Recording play count */ + uint32_t de_playposition; /* Recording last played position in seconds */ /** * EPG information / links @@ -542,7 +544,8 @@ dvr_entry_update( dvr_entry_t *de, int enabled, const char *desc, const char *lang, time_t start, time_t stop, time_t start_extra, time_t stop_extra, - dvr_prio_t pri, int retention, int removal ); + dvr_prio_t pri, int retention, int removal, + int playcount, int playposition); void dvr_destroy_by_channel(channel_t *ch, int delconf); @@ -604,6 +607,8 @@ htsmsg_t *dvr_entry_class_removal_list ( void *o, const char *lang ); int dvr_entry_verify(dvr_entry_t *de, access_t *a, int readonly); +void dvr_entry_changed_notify(dvr_entry_t *de); + void dvr_spawn_cmd(dvr_entry_t *de, const char *cmd, const char *filename, int pre); void dvr_vfs_refresh_entry(dvr_entry_t *de); diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 9465101bf..e1ec10306 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -146,6 +146,16 @@ dvr_entry_verify(dvr_entry_t *de, access_t *a, int readonly) return 0; } +/* + * + */ +void +dvr_entry_changed_notify(dvr_entry_t *de) +{ + idnode_changed(&de->de_id); + htsp_dvr_entry_update(de); +} + /* * */ @@ -213,9 +223,7 @@ dvr_entry_dont_rerecord(dvr_entry_t *de, int dont_rerecord) if (de->de_dont_rerecord ? 1 : 0 != dont_rerecord) { dvr_entry_trace(de, "don't rerecord change %d", dont_rerecord); de->de_dont_rerecord = dont_rerecord; - idnode_changed(&de->de_id); - idnode_notify_changed(&de->de_id); - htsp_dvr_entry_update(de); + dvr_entry_changed_notify(de); } } @@ -1550,6 +1558,8 @@ dvr_timer_remove_files(void *aux) #define DVR_UPDATED_BROADCAST (1<<15) #define DVR_UPDATED_EPISODE (1<<16) #define DVR_UPDATED_CONFIG (1<<17) +#define DVR_UPDATED_PLAYPOS (1<<18) +#define DVR_UPDATED_PLAYCOUNT (1<<19) static char *dvr_updated_str(char *buf, size_t buflen, int flags) { @@ -1576,7 +1586,8 @@ static dvr_entry_t *_dvr_entry_update const char *title, const char *subtitle, const char *desc, const char *lang, time_t start, time_t stop, time_t start_extra, time_t stop_extra, - dvr_prio_t pri, int retention, int removal ) + dvr_prio_t pri, int retention, int removal, + int playcount, int playposition) { char buf[40]; int save = 0, updated = 0; @@ -1608,6 +1619,16 @@ static dvr_entry_t *_dvr_entry_update updated = 1; dvr_entry_set_timer(de); } + if (de->de_sched_state == DVR_RECORDING || de->de_sched_state == DVR_COMPLETED) { + if (playcount >= 0 && playcount != de->de_playcount) { + de->de_playcount = playcount; + save |= DVR_UPDATED_PLAYCOUNT; + } + if (playposition >= 0 && playposition != de->de_playposition) { + de->de_playposition = playposition; + save |= DVR_UPDATED_PLAYPOS; + } + } goto dosave; } @@ -1721,8 +1742,7 @@ static dvr_entry_t *_dvr_entry_update /* Save changes */ dosave: if (save) { - idnode_changed(&de->de_id); - htsp_dvr_entry_update(de); + dvr_entry_changed_notify(de); if (tvhlog_limit(&de->de_update_limit, 60)) { tvhinfo(LS_DVR, "\"%s\" on \"%s\": Updated%s (%s)", lang_str_get(de->de_title, NULL), DVR_CH_NAME(de), @@ -1750,12 +1770,12 @@ dvr_entry_update const char *desc, const char *lang, time_t start, time_t stop, time_t start_extra, time_t stop_extra, - dvr_prio_t pri, int retention, int removal ) + dvr_prio_t pri, int retention, int removal, int playcount, int playposition ) { return _dvr_entry_update(de, enabled, dvr_config_uuid, NULL, ch, title, subtitle, desc, lang, start, stop, start_extra, stop_extra, - pri, retention, removal); + pri, retention, removal, playcount, playposition); } /** @@ -1809,7 +1829,7 @@ dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e) gmtime2local(e2->start, t1buf, sizeof(t1buf)), gmtime2local(e2->stop, t2buf, sizeof(t2buf))); _dvr_entry_update(de, -1, NULL, e2, NULL, NULL, NULL, NULL, NULL, - 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0); + 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0, -1, -1); return; } } @@ -1851,7 +1871,7 @@ void dvr_event_updated(epg_broadcast_t *e) if (de->de_bcast != e) continue; _dvr_entry_update(de, -1, NULL, e, NULL, NULL, NULL, NULL, - NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0); + NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0, -1, -1); found++; } if (found == 0) { @@ -1865,7 +1885,7 @@ void dvr_event_updated(epg_broadcast_t *e) epg_broadcast_get_title(e, NULL), channel_get_name(e->channel)); _dvr_entry_update(de, -1, NULL, e, NULL, NULL, NULL, NULL, - NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0); + NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0, 0, -1, -1); break; } } @@ -3112,6 +3132,24 @@ const idclass_t dvr_entry_class = { .list = dvr_entry_class_removal_list, .opts = PO_HIDDEN | PO_ADVANCED | PO_DOC_NLIST, }, + { + .type = PT_U32, + .id = "playposition", + .name = N_("Last played position"), + .desc = N_("Last played position when the recording isn't fully watched yet."), + .off = offsetof(dvr_entry_t, de_playposition), + .def.i = 0, + .opts = PO_HIDDEN | PO_NOUI | PO_DOC_NLIST, + }, + { + .type = PT_U32, + .id = "playcount", + .name = N_("Recording play count"), + .desc = N_("Number of times this recording was played."), + .off = offsetof(dvr_entry_t, de_playcount), + .def.i = 0, + .opts = PO_HIDDEN | PO_EXPERT | PO_DOC_NLIST, + }, { .type = PT_STR, .id = "config_name", diff --git a/src/htsp_server.c b/src/htsp_server.c index f30be8f95..530cb87f9 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -933,6 +933,11 @@ htsp_build_dvrentry(htsp_connection_t *htsp, dvr_entry_t *de, const char *method htsmsg_add_u32(out, "priority", de->de_pri); htsmsg_add_u32(out, "contentType", de->de_content_type); + if (de->de_sched_state == DVR_RECORDING || de->de_sched_state == DVR_COMPLETED) { + htsmsg_add_u32(out, "playcount", de->de_playcount); + htsmsg_add_u32(out, "playposition", de->de_playposition); + } + if(de->de_title && (s = lang_str_get(de->de_title, lang))) htsmsg_add_str(out, "title", s); if(de->de_subtitle && (s = lang_str_get(de->de_subtitle, lang))) @@ -1915,10 +1920,10 @@ htsp_method_updateDvrEntry(htsp_connection_t *htsp, htsmsg_t *in) htsmsg_t *out = NULL; uint32_t u32; dvr_entry_t *de; - time_t start, stop, start_extra, stop_extra, priority, retention, removal; + time_t start, stop, start_extra, stop_extra, priority; const char *dvr_config_name, *title, *subtitle, *desc, *lang; channel_t *channel = NULL; - int enabled; + int enabled, retention, removal, playcount = -1, playposition = -1; de = htsp_findDvrEntry(htsp, in, &out, 0); if (de == NULL) @@ -1947,9 +1952,14 @@ htsp_method_updateDvrEntry(htsp_connection_t *htsp, htsmsg_t *in) desc = htsmsg_get_str(in, "description"); lang = htsmsg_get_str(in, "language") ?: htsp->htsp_language; + if(!htsmsg_get_u32(in, "playcount", &u32)) + playcount = u32 > INT_MAX ? INT_MAX : u32; + if(!htsmsg_get_u32(in, "playposition", &u32)) + playposition = u32 > INT_MAX ? INT_MAX : u32; + de = dvr_entry_update(de, enabled, dvr_config_name, channel, title, subtitle, desc, lang, start, stop, start_extra, stop_extra, - priority, retention, removal); + priority, retention, removal, playcount, playposition); return htsp_success(); } diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index e8e6d60e5..1f8a19ef5 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -454,11 +454,11 @@ tvheadend.dvr_finished = function(panel, index) { titleP: _('Finished Recordings'), iconCls: 'finishedRec', tabIndex: index, - edit: { params: { list: tvheadend.admin ? "retention,removal,owner,comment" : "retention,removal,comment" } }, + edit: { params: { list: tvheadend.admin ? "playcount,retention,removal,owner,comment" : "retention,removal,comment" } }, del: false, list: 'disp_title,disp_subtitle,episode,channelname,' + 'start_real,stop_real,duration,filesize,' + - 'sched_status,errors,data_errors,url,config_name,owner,creator,comment', + 'sched_status,errors,data_errors,playcount,url,config_name,owner,creator,comment', columns: { filesize: { renderer: tvheadend.filesizeRenderer() @@ -589,13 +589,13 @@ tvheadend.dvr_failed = function(panel, index) { titleP: _('Failed Recordings'), iconCls: 'exclamation', tabIndex: index, - edit: { params: { list: tvheadend.admin ? "retention,removal,owner,comment" : "retention,removal,comment" } }, + edit: { params: { list: tvheadend.admin ? "playcount,retention,removal,owner,comment" : "retention,removal,comment" } }, del: true, delquestion: _('Do you really want to delete the selected recordings?') + '

' + _('The associated file will be removed from storage.'), list: 'disp_title,disp_subtitle,episode,channelname,' + 'start_real,stop_real,duration,filesize,status,' + - 'sched_status,errors,data_errors,url,config_name,owner,creator,comment', + 'sched_status,errors,data_errors,playcount,url,config_name,owner,creator,comment', columns: { filesize: { renderer: tvheadend.filesizeRenderer() diff --git a/src/webui/webui.c b/src/webui/webui.c index 0fa2afd15..ba6e87ceb 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -1523,6 +1523,12 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) return HTTP_STATUS_UNAUTHORIZED; } + /* Play count + 1 when write access */ + if (!dvr_entry_verify(de, hc->hc_access, 0)) { + de->de_playcount = de->de_playcount + 1; + dvr_entry_changed_notify(de); + } + fname = tvh_strdupa(filename); content = muxer_container_filename2mime(fname, 1); charset = de->de_config ? de->de_config->dvr_charset_id : NULL;