]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
* Add support for storing recorded events in a directory named after
authorAndreas Öman <andreas@lonelycoder.com>
Tue, 16 Mar 2010 22:59:10 +0000 (22:59 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Tue, 16 Mar 2010 22:59:10 +0000 (22:59 +0000)
    the event. Ticket #150

  * Add support for appending season and episode numbers to filenames
    during recording.

debian/changelog
src/dvr/dvr.h
src/dvr/dvr_db.c
src/dvr/dvr_rec.c
src/webui/extjs.c
src/webui/static/app/dvr.js

index 8256c1a0a3f6089bc6068db81c9d0e0a05dc8920..a4c240c71007a1b0d973d7e078ffe06d19bb0725 100644 (file)
@@ -23,6 +23,12 @@ hts-tvheadend (2.11-WIP) hts; urgency=low
     or when a new auto recording was created from the EPG view). This
     is now fixed.
 
+  * Add support for storing recorded events in a directory named after
+    the event. Ticket #150
+
+  * Add support for appending season and episode numbers to filenames
+    during recording.
+
 hts-tvheadend (2.10) hts; urgency=high
 
   * Fix a crash in HTSP server.
index f3699a0c0f71d05e6706b9fe049aa18274c93547..9b1fe30662f66ba805b82aecb88387f7e5204247 100644 (file)
@@ -41,6 +41,8 @@ extern struct dvr_entry_list dvrentries;
 #define DVR_DATE_IN_TITLE      0x8
 #define DVR_TIME_IN_TITLE      0x10
 #define DVR_WHITESPACE_IN_TITLE        0x20
+#define DVR_DIR_PER_TITLE      0x40
+#define DVR_EPISODE_IN_TITLE   0x80
 
 LIST_HEAD(dvr_rec_stream_list, dvr_rec_stream);
 
@@ -91,6 +93,8 @@ typedef struct dvr_entry {
                          date and time pre/post/fixed */
   char *de_desc;       /* Description in UTF-8 (from EPG) */
 
+  epg_episode_t de_episode;
+
   char *de_error;
 
   dvr_entry_sched_state_t de_sched_state;
@@ -176,7 +180,8 @@ dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator,
 
 dvr_entry_t *dvr_entry_create(channel_t *ch, time_t start, time_t stop, 
                              const char *title, const char *description,
-                             const char *creator, dvr_autorec_entry_t *dae);
+                             const char *creator, dvr_autorec_entry_t *dae,
+                             epg_episode_t *ee);
 
 void dvr_init(void);
 
index 850bee6f3d784a4c6de6db956913ddc5e3976a42..d14651dfaf0e5bad81b852513ee1f823ed23d079 100644 (file)
@@ -67,21 +67,20 @@ dvrdb_changed(void)
  *
  */
 static void
-dvr_make_title(char *output, size_t outlen, const char *title,
-              const char *channel, time_t starttime)
+dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
 {
   struct tm tm;
   char buf[40];
 
   if(dvr_flags & DVR_CHANNEL_IN_TITLE)
-    snprintf(output, outlen, "%s-", channel);
+    snprintf(output, outlen, "%s-", de->de_channel->ch_name);
   else
     output[0] = 0;
   
   snprintf(output + strlen(output), outlen - strlen(output),
-          "%s", title);
+          "%s", de->de_title);
 
-  localtime_r(&starttime, &tm);
+  localtime_r(&de->de_start, &tm);
   
   if(dvr_flags & DVR_DATE_IN_TITLE) {
     strftime(buf, sizeof(buf), "%F", &tm);
@@ -92,6 +91,19 @@ dvr_make_title(char *output, size_t outlen, const char *title,
     strftime(buf, sizeof(buf), "%H-%M", &tm);
     snprintf(output + strlen(output), outlen - strlen(output), "-%s", buf);
   }
+
+  if(dvr_flags & DVR_EPISODE_IN_TITLE) {
+
+    if(de->de_episode.ee_season && de->de_episode.ee_episode)
+      snprintf(output + strlen(output), outlen - strlen(output), 
+              ".S%02dE%02d",
+              de->de_episode.ee_season, de->de_episode.ee_episode);
+
+    else if(de->de_episode.ee_episode)
+      snprintf(output + strlen(output), outlen - strlen(output), 
+              ".E%02d",
+              de->de_episode.ee_episode);
+  }
 }
 
 
@@ -104,8 +116,7 @@ dvr_entry_link(dvr_entry_t *de)
   time_t now, preamble;
   char buf[100];
 
-  dvr_make_title(buf, sizeof(buf), de->de_title, de->de_channel->ch_name,
-                de->de_start);
+  dvr_make_title(buf, sizeof(buf), de);
 
   de->de_ititle = strdup(buf);
 
@@ -137,7 +148,8 @@ dvr_entry_link(dvr_entry_t *de)
 dvr_entry_t *
 dvr_entry_create(channel_t *ch, time_t start, time_t stop, 
                 const char *title, const char *description,
-                const char *creator, dvr_autorec_entry_t *dae)
+                const char *creator, dvr_autorec_entry_t *dae,
+                epg_episode_t *ee)
 {
   dvr_entry_t *de;
   char tbuf[30];
@@ -168,14 +180,23 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop,
   de->de_title   = strdup(title);
   de->de_desc    = description ? strdup(description) : NULL;
 
+  if(ee != NULL) {
+    de->de_episode.ee_season  = ee->ee_season;
+    de->de_episode.ee_episode = ee->ee_episode;
+    de->de_episode.ee_part    = ee->ee_part;
+    tvh_str_set(&de->de_episode.ee_onscreen, ee->ee_onscreen);
+  }
+
   dvr_entry_link(de);
 
   t = de->de_start - de->de_start_extra * 60;
   localtime_r(&t, &tm);
   strftime(tbuf, sizeof(tbuf), "%c", &tm);
 
-  de->de_autorec = dae;
-  LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link);
+  if(dae != NULL) {
+    de->de_autorec = dae;
+    LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link);
+  }
 
   tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\" starting at %s, "
         "scheduled for recording by \"%s\"",
@@ -198,7 +219,7 @@ dvr_entry_create_by_event(event_t *e, const char *creator,
     return NULL;
 
   return dvr_entry_create(e->e_channel, e->e_start, e->e_stop, 
-                         e->e_title, e->e_desc, creator, dae);
+                         e->e_title, e->e_desc, creator, dae, &e->e_episode);
 }
 
 
@@ -236,6 +257,8 @@ dvr_entry_dec_ref(dvr_entry_t *de)
   free(de->de_ititle);
   free(de->de_desc);
 
+  free(de->de_episode.ee_onscreen);
+
   free(de);
 }
 
@@ -332,6 +355,15 @@ dvr_db_load_one(htsmsg_t *c, int id)
     }
   }
 
+  if(!htsmsg_get_s32(c, "season", &d))
+    de->de_episode.ee_season = d;
+  if(!htsmsg_get_s32(c, "episode", &d))
+    de->de_episode.ee_episode = d;
+  if(!htsmsg_get_s32(c, "part", &d))
+    de->de_episode.ee_part = d;
+
+  tvh_str_set(&de->de_episode.ee_onscreen, htsmsg_get_str(c, "episodename"));
+
   dvr_entry_link(de);
 }
 
@@ -393,6 +425,15 @@ dvr_entry_save(dvr_entry_t *de)
   if(de->de_autorec != NULL)
     htsmsg_add_str(m, "autorec", de->de_autorec->dae_id);
 
+  if(de->de_episode.ee_season)
+    htsmsg_add_u32(m, "season", de->de_episode.ee_season);
+  if(de->de_episode.ee_episode)
+    htsmsg_add_u32(m, "episode", de->de_episode.ee_episode);
+  if(de->de_episode.ee_part)
+    htsmsg_add_u32(m, "part", de->de_episode.ee_part);
+  if(de->de_episode.ee_onscreen)
+    htsmsg_add_str(m, "episodename", de->de_episode.ee_onscreen);
+
   hts_settings_save(m, "dvr/log/%d", de->de_id);
   htsmsg_destroy(m);
 }
@@ -594,6 +635,12 @@ dvr_init(void)
  
     if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
       dvr_flags |= DVR_WHITESPACE_IN_TITLE;
+
+    if(!htsmsg_get_u32(m, "title-dir", &u32) && u32)
+      dvr_flags |= DVR_DIR_PER_TITLE;
+
+    if(!htsmsg_get_u32(m, "episode-in-title", &u32) && u32)
+      dvr_flags |= DVR_EPISODE_IN_TITLE;
    
     tvh_str_set(&dvr_postproc, htsmsg_get_str(m, "postproc"));
 
@@ -645,6 +692,8 @@ dvr_save(void)
   htsmsg_add_u32(m, "date-in-title",    !!(dvr_flags & DVR_DATE_IN_TITLE));
   htsmsg_add_u32(m, "time-in-title",    !!(dvr_flags & DVR_TIME_IN_TITLE));
   htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
+  htsmsg_add_u32(m, "title-dir", !!(dvr_flags & DVR_DIR_PER_TITLE));
+  htsmsg_add_u32(m, "episode-in-title", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
   if(dvr_postproc != NULL)
     htsmsg_add_str(m, "postproc", dvr_postproc);
 
index ac8a05f4425bd9d31f3b10e6c8820effaea6d02e..d41ebad69fe4c3e17d51e2fa09e13aa59574ddbe 100644 (file)
@@ -170,7 +170,6 @@ pvr_generate_filename(dvr_entry_t *de)
   int tally = 0;
   struct stat st;
   char *filename;
-  char *chname;
   struct tm tm;
 
   filename = strdup(de->de_ititle);
@@ -192,13 +191,25 @@ pvr_generate_filename(dvr_entry_t *de)
 
   if(dvr_flags & DVR_DIR_PER_CHANNEL) {
 
-    chname = strdup(de->de_channel->ch_name);
+    char *chname = strdup(de->de_channel->ch_name);
     cleanupfilename(chname);
     snprintf(path + strlen(path), sizeof(path) - strlen(path), 
             "/%s", chname);
     free(chname);
   }
 
+  /* Append per-title directory */
+
+  if(dvr_flags & DVR_DIR_PER_TITLE) {
+
+    char *title = strdup(de->de_title);
+    cleanupfilename(title);
+    snprintf(path + strlen(path), sizeof(path) - strlen(path), 
+            "/%s", title);
+    free(title);
+  }
+
+
   /* */
   if(makedirs(path) != 0)
     return -1;
index c7de96146867f7fcfb3e3da1238e238a39c188d2..347eb924621d619638bfb2174aa21c53b35814c4 100644 (file)
@@ -780,7 +780,8 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
     if(stop < start)
       stop += 86400;
 
-    dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative, NULL);
+    dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative, 
+                    NULL, NULL);
 
     out = htsmsg_create_map();
     htsmsg_add_u32(out, "success", 1);
@@ -810,7 +811,9 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
     htsmsg_add_u32(r, "channelInTitle", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
     htsmsg_add_u32(r, "dateInTitle",    !!(dvr_flags & DVR_DATE_IN_TITLE));
     htsmsg_add_u32(r, "timeInTitle",    !!(dvr_flags & DVR_TIME_IN_TITLE));
-    htsmsg_add_u32(r, "whitespaceInTitle",    !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
+    htsmsg_add_u32(r, "whitespaceInTitle", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
+    htsmsg_add_u32(r, "titleDirs", !!(dvr_flags & DVR_DIR_PER_TITLE));
+    htsmsg_add_u32(r, "episodeInTitle", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
 
     out = json_single_record(r, "dvrSettings");
 
@@ -843,6 +846,10 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
       flags |= DVR_TIME_IN_TITLE;
     if(http_arg_get(&hc->hc_req_args, "whitespaceInTitle") != NULL)
       flags |= DVR_WHITESPACE_IN_TITLE;
+    if(http_arg_get(&hc->hc_req_args, "titleDirs") != NULL)
+      flags |= DVR_DIR_PER_TITLE;
+    if(http_arg_get(&hc->hc_req_args, "episodeInTitle") != NULL)
+      flags |= DVR_EPISODE_IN_TITLE;
 
     dvr_flags_set(flags);
 
@@ -924,6 +931,9 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
     if(de->de_desc != NULL)
       htsmsg_add_str(m, "description", de->de_desc);
 
+    if(de->de_episode.ee_onscreen)
+      htsmsg_add_str(m, "episode", de->de_episode.ee_onscreen);
+
     htsmsg_add_u32(m, "id", de->de_id);
     htsmsg_add_u32(m, "start", de->de_start);
     htsmsg_add_u32(m, "end", de->de_stop);
index ad26f85faf52dcdef0c1cd2cb8b772231e9a1089..b307277d6cf291c1d04825d203cbfeb351bc761a 100644 (file)
@@ -116,6 +116,11 @@ tvheadend.dvrschedule = function() {
            id:'title',
            header: "Title",
            dataIndex: 'title'
+       },{
+           width: 250,
+           id:'episode',
+           header: "Episode",
+           dataIndex: 'episode'
        },{
            width: 100,
            id:'start',
@@ -388,6 +393,7 @@ tvheadend.dvr = function() {
            {name: 'id'},
            {name: 'channel'},
            {name: 'title'},
+           {name: 'episode'},
            {name: 'description'},
            {name: 'chicon'},
             {name: 'start', type: 'date', dateFormat: 'U' /* unix time */},
@@ -456,7 +462,8 @@ tvheadend.dvrsettings = function() {
     }, ['storage','postproc','retention','dayDirs',
        'channelDirs','channelInTitle',
        'dateInTitle','timeInTitle',
-       'preExtraTime', 'postExtraTime', 'whitespaceInTitle']);
+       'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 
+       'titleDirs', 'episodeInTitle']);
 
     var confpanel = new Ext.FormPanel({
        title:'Digital Video Recorder',
@@ -495,14 +502,20 @@ tvheadend.dvrsettings = function() {
            fieldLabel: 'Make subdirectories per channel',
            name: 'channelDirs'
        }), new Ext.form.Checkbox({
-           fieldLabel: 'Include channel name in title',
+           fieldLabel: 'Make subdirectories per title',
+           name: 'titleDirs'
+       }), new Ext.form.Checkbox({
+           fieldLabel: 'Include channel name in filename',
            name: 'channelInTitle'
        }), new Ext.form.Checkbox({
-           fieldLabel: 'Include date in title',
+           fieldLabel: 'Include date in filename',
            name: 'dateInTitle'
        }), new Ext.form.Checkbox({
-           fieldLabel: 'Include time in title',
+           fieldLabel: 'Include time in filename',
            name: 'timeInTitle'
+       }), new Ext.form.Checkbox({
+           fieldLabel: 'Include episode in filename',
+           name: 'episodeInTitle'
        }), new Ext.form.Checkbox({
            fieldLabel: 'Replace whitespace in title with \'-\'',
            name: 'whitespaceInTitle'