]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Implement playcount and playposition
authorGlenn-1990 <g_christiaensen@msn.com>
Fri, 4 Nov 2016 14:25:38 +0000 (15:25 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 24 Nov 2016 13:57:49 +0000 (14:57 +0100)
src/dvr/dvr.h
src/dvr/dvr_db.c
src/htsp_server.c
src/webui/static/app/dvr.js
src/webui/webui.c

index 054dcd129f4261d24164a4649e29d09325657702..bd324b6de9ae970bf32b50b62764e074468acf55 100644 (file)
@@ -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);
index 9465101bf66eeb4ae2352256dc69340cd5d5bb59..e1ec1030620833811a11464fced31ff1a8db1f80 100644 (file)
@@ -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",
index f30be8f955688498b7ad5a36a0f41b958a5ba544..530cb87f9f7078ab3a30d19a1f240e548dc81a5a 100644 (file)
@@ -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();
 }
index e8e6d60e5e478918c6b4389ef299e7d44157d94a..1f8a19ef5d7ac3672a0e21af39301a06448fd3df 100644 (file)
@@ -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?') + '<br/><br/>' +
                      _('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()
index 0fa2afd15c8ccc1590aeafc70baaf38590c6087e..ba6e87ceb75eb25409c9faa131438c9fe9d3a1f2 100644 (file)
@@ -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;