Project

General

Profile

Feature #303 » dvrconfig.patch

The patch - sbi -, 2010-10-10 21:56

View differences:

tvheadend/src/dvb/dvb_fe.c
39 39
#include "diseqc.h"
40 40
#include "notify.h"
41 41
#include "transports.h"
42

  
42
#include "dvr/dvr.h"
43 43

  
44 44
/**
45 45
 * Front end monitor
......
197 197
  struct dmx_pes_filter_params dmx_param;
198 198
  char fullname[1000];
199 199
  char path[500];
200
  extern char *dvr_storage;
201 200
  const char *fname = tda->tda_mux_current->tdmi_identifier;
202 201

  
203 202
  int fd = tvh_open(tda->tda_demux_path, O_RDWR, 0);
......
220 219
    return;
221 220
  }
222 221

  
223
  snprintf(path, sizeof(path), "%s/muxdumps", dvr_storage);
222
  snprintf(path, sizeof(path), "%s/muxdumps", 
223
      dvr_config_find_by_name_default("")->dvr_storage);
224 224

  
225 225
  if(mkdir(path, 0777) && errno != EEXIST) {
226 226
    tvhlog(LOG_ERR, "dvb", "\"%s\" unable to create mux dump dir %s -- %s",
tvheadend/src/dvr/dvr.h
24 24
#include "channels.h"
25 25
#include "subscriptions.h"
26 26

  
27
extern char *dvr_storage;
28
extern char *dvr_format;
29
extern char *dvr_file_postfix;
30
extern uint32_t dvr_retention_days;
31
extern int dvr_flags;
32
extern char *dvr_postproc;
33
extern int dvr_extra_time_pre;
34
extern int dvr_extra_time_post;
27
typedef struct dvr_config {
28
  char *dvr_config_name;
29
  char *dvr_storage;
30
  char *dvr_format;
31
  char *dvr_file_postfix;
32
  uint32_t dvr_retention_days;
33
  int dvr_flags;
34
  char *dvr_postproc;
35
  int dvr_extra_time_pre;
36
  int dvr_extra_time_post;
37

  
38
  LIST_ENTRY(dvr_config) config_link;
39
} dvr_config_t;
40

  
41
extern struct dvr_config_list dvrconfigs;
42

  
35 43
extern struct dvr_entry_list dvrentries;
36 44

  
37 45
#define DVR_DIR_PER_DAY		0x1
......
98 106
   * These meta fields will stay valid as long as reference count > 0
99 107
   */
100 108

  
109
  char *de_config_name;
110

  
101 111
  time_t de_start;
102 112
  time_t de_stop;
103 113

  
......
172 182
  TAILQ_ENTRY(dvr_autorec_entry) dae_link;
173 183
  char *dae_id;
174 184

  
185
  char *dae_config_name;
186

  
175 187
  int dae_enabled;
176 188
  char *dae_creator;
177 189
  char *dae_comment;
......
202 214
 * Prototypes
203 215
 */
204 216

  
217
dvr_config_t *dvr_config_find_by_name(const char *name);
218

  
219
dvr_config_t *dvr_config_find_by_name_default(const char *name);
220

  
221
dvr_config_t *dvr_config_create(const char *name);
222

  
223
void dvr_config_delete(const char *name);
224

  
205 225
void dvr_entry_notify(dvr_entry_t *de);
206 226

  
207 227
const char *dvr_entry_status(dvr_entry_t *de);
......
210 230

  
211 231
void dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae);
212 232

  
213
dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator,
233
dvr_entry_t *dvr_entry_create_by_event(const char *dvr_config_name,
234
                                       event_t *e, const char *creator,
214 235
				       dvr_autorec_entry_t *dae,
215 236
				       dvr_prio_t pri);
216 237

  
217
dvr_entry_t *dvr_entry_create(channel_t *ch, time_t start, time_t stop, 
238
dvr_entry_t *dvr_entry_create(const char *dvr_config_name,
239
                              channel_t *ch, time_t start, time_t stop, 
218 240
			      const char *title, const char *description,
219 241
			      const char *creator, dvr_autorec_entry_t *dae,
220 242
			      epg_episode_t *ee, uint8_t content_type,
......
240 262

  
241 263
void dvr_entry_dec_ref(dvr_entry_t *de);
242 264

  
243
void dvr_storage_set(const char *storage);
265
void dvr_storage_set(dvr_config_t *cfg, const char *storage);
244 266

  
245
void dvr_postproc_set(const char *postproc);
267
void dvr_postproc_set(dvr_config_t *cfg, const char *postproc);
246 268

  
247
void dvr_retention_set(int days);
269
void dvr_retention_set(dvr_config_t *cfg, int days);
248 270

  
249
void dvr_flags_set(int flags);
271
void dvr_flags_set(dvr_config_t *cfg, int flags);
250 272

  
251
void dvr_extra_time_pre_set(int d);
273
void dvr_extra_time_pre_set(dvr_config_t *cfg, int d);
252 274

  
253
void dvr_extra_time_post_set(int d);
275
void dvr_extra_time_post_set(dvr_config_t *cfg, int d);
254 276

  
255 277
/**
256 278
 * Query interface
......
268 290
/**
269 291
 *
270 292
 */
271
void dvr_autorec_add(const char *title, const char *channel,
293
void dvr_autorec_add(const char *dvr_config_name,
294
                     const char *title, const char *channel,
272 295
		     const char *tag, uint8_t content_type,
273 296
		     const char *creator, const char *comment);
274 297

  
tvheadend/src/dvr/dvr_autorec.c
166 166

  
167 167
  free(dae->dae_id);
168 168

  
169
  free(dae->dae_config_name);
169 170
  free(dae->dae_creator);
170 171
  free(dae->dae_comment);
171 172

  
......
227 228
  htsmsg_add_str(e, "id", dae->dae_id);
228 229
  htsmsg_add_u32(e, "enabled",  !!dae->dae_enabled);
229 230

  
231
  if (dae->dae_config_name != NULL)
232
    htsmsg_add_str(e, "config_name", dae->dae_config_name);
230 233
  if(dae->dae_creator != NULL)
231 234
    htsmsg_add_str(e, "creator", dae->dae_creator);
232 235
  if(dae->dae_comment != NULL)
......
307 310
  if((dae = autorec_entry_find(id, maycreate)) == NULL)
308 311
    return NULL;
309 312

  
313
  tvh_str_update(&dae->dae_config_name, htsmsg_get_str(values, "config_name"));
310 314
  tvh_str_update(&dae->dae_creator, htsmsg_get_str(values, "creator"));
311 315
  tvh_str_update(&dae->dae_comment, htsmsg_get_str(values, "comment"));
312 316

  
......
417 421
 *
418 422
 */
419 423
void
420
dvr_autorec_add(const char *title, const char *channel,
424
dvr_autorec_add(const char *config_name,
425
                const char *title, const char *channel,
421 426
		const char *tag, uint8_t content_type,
422 427
		const char *creator, const char *comment)
423 428
{
......
429 434
  if((dae = autorec_entry_find(NULL, 1)) == NULL)
430 435
    return;
431 436

  
437
  tvh_str_set(&dae->dae_config_name, config_name);
432 438
  tvh_str_set(&dae->dae_creator, creator);
433 439
  tvh_str_set(&dae->dae_comment, comment);
434 440

  
tvheadend/src/dvr/dvr_db.c
30 30
#include "htsp.h"
31 31
#include "streaming.h"
32 32

  
33
char *dvr_storage;
34
char *dvr_format;
35
char *dvr_file_postfix;
36
uint32_t dvr_retention_days;
37
int dvr_flags;
38
int dvr_extra_time_pre;
39
int dvr_extra_time_post;
40
char *dvr_postproc;
41
int dvr_iov_max;
42

  
43 33
static int de_tally;
44 34

  
35
int dvr_iov_max;
36

  
37
struct dvr_config_list dvrconfigs;
45 38
struct dvr_entry_list dvrentries;
46 39

  
47 40
static void dvr_entry_save(dvr_entry_t *de);
......
129 122
  notify_by_msg("dvrdb", m);
130 123
}
131 124

  
125
/**
126
 *
127
 */
128
static void
129
dvrconfig_changed(void)
130
{
131
  htsmsg_t *m = htsmsg_create_map();
132
  htsmsg_add_u32(m, "reload", 1);
133
  notify_by_msg("dvrconfig", m);
134
}
135

  
132 136

  
133 137
/**
134 138
 *
......
155 159
  struct tm tm;
156 160
  char buf[40];
157 161
  int i;
162
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
158 163

  
159
  if(dvr_flags & DVR_CHANNEL_IN_TITLE)
164
  if(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE)
160 165
    snprintf(output, outlen, "%s-", de->de_channel->ch_name);
161 166
  else
162 167
    output[0] = 0;
......
166 171

  
167 172
  localtime_r(&de->de_start, &tm);
168 173
  
169
  if(dvr_flags & DVR_DATE_IN_TITLE) {
174
  if(cfg->dvr_flags & DVR_DATE_IN_TITLE) {
170 175
    strftime(buf, sizeof(buf), "%F", &tm);
171 176
    snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
172 177
  }
173 178

  
174
  if(dvr_flags & DVR_TIME_IN_TITLE) {
179
  if(cfg->dvr_flags & DVR_TIME_IN_TITLE) {
175 180
    strftime(buf, sizeof(buf), "%H-%M", &tm);
176 181
    snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
177 182
  }
178 183

  
179
  if(dvr_flags & DVR_EPISODE_IN_TITLE) {
184
  if(cfg->dvr_flags & DVR_EPISODE_IN_TITLE) {
180 185

  
181 186
    if(de->de_episode.ee_season && de->de_episode.ee_episode)
182 187
      snprintf(output + strlen(output), outlen - strlen(output), 
......
189 194
	       de->de_episode.ee_episode);
190 195
  }
191 196

  
192
  if(dvr_flags & DVR_CLEAN_TITLE) {
197
  if(cfg->dvr_flags & DVR_CLEAN_TITLE) {
193 198
        for (i=0;i<strlen(output);i++) {
194 199
                if (
195 200
                        output[i]<32 ||
......
212 217
{
213 218
  time_t now, preamble;
214 219
  char buf[100];
220
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
215 221

  
216 222
  dvr_make_title(buf, sizeof(buf), de);
217 223

  
......
231 237
    else
232 238
      de->de_sched_state = DVR_COMPLETED;
233 239
    gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, 
234
	       de->de_stop + dvr_retention_days * 86400);
240
	       de->de_stop + cfg->dvr_retention_days * 86400);
235 241

  
236 242
  } else {
237 243
    de->de_sched_state = DVR_SCHEDULED;
......
246 252
 *
247 253
 */
248 254
dvr_entry_t *
249
dvr_entry_create(channel_t *ch, time_t start, time_t stop, 
255
dvr_entry_create(const char *config_name,
256
                 channel_t *ch, time_t start, time_t stop, 
250 257
		 const char *title, const char *description,
251 258
		 const char *creator, dvr_autorec_entry_t *dae,
252 259
		 epg_episode_t *ee, uint8_t content_type, dvr_prio_t pri)
......
255 262
  char tbuf[30];
256 263
  struct tm tm;
257 264
  time_t t;
265
  dvr_config_t *cfg = dvr_config_find_by_name_default(config_name);
258 266

  
259 267
  LIST_FOREACH(de, &ch->ch_dvrs, de_channel_link)
260 268
    if(de->de_start == start && de->de_sched_state != DVR_COMPLETED)
......
272 280
  if (ch->ch_dvr_extra_time_pre)
273 281
    de->de_start_extra = ch->ch_dvr_extra_time_pre;
274 282
  else
275
    de->de_start_extra = dvr_extra_time_pre;
283
    de->de_start_extra = cfg->dvr_extra_time_pre;
276 284
  if (ch->ch_dvr_extra_time_post)
277 285
    de->de_stop_extra  = ch->ch_dvr_extra_time_post;
278 286
  else
279
    de->de_stop_extra  = dvr_extra_time_post;
287
    de->de_stop_extra  = cfg->dvr_extra_time_post;
288
  de->de_config_name = strdup(cfg->dvr_config_name);
280 289
  de->de_creator = strdup(creator);
281 290
  de->de_title   = strdup(title);
282 291
  de->de_desc    = description ? strdup(description) : NULL;
......
315 324
 *
316 325
 */
317 326
dvr_entry_t *
318
dvr_entry_create_by_event(event_t *e, const char *creator, 
327
dvr_entry_create_by_event(const char *config_name,
328
                          event_t *e, const char *creator, 
319 329
			  dvr_autorec_entry_t *dae, dvr_prio_t pri)
320 330
{
321 331
  if(e->e_channel == NULL || e->e_title == NULL)
322 332
    return NULL;
323 333

  
324
  return dvr_entry_create(e->e_channel, e->e_start, e->e_stop, 
334
  return dvr_entry_create(config_name,
335
                          e->e_channel, e->e_start, e->e_stop, 
325 336
			  e->e_title, e->e_desc, creator, dae, &e->e_episode,
326 337
			  e->e_content_type, pri);
327 338
}
......
340 351
  } else {
341 352
    snprintf(buf, sizeof(buf), "Auto recording");
342 353
  }
343
  dvr_entry_create_by_event(e, buf, dae, dae->dae_pri);
354
  dvr_entry_create_by_event(dae->dae_config_name, e, buf, dae, dae->dae_pri);
344 355
}
345 356

  
346 357

  
......
360 371
  if(de->de_autorec != NULL)
361 372
    LIST_REMOVE(de, de_autorec_link);
362 373

  
374
  free(de->de_config_name);
363 375
  free(de->de_creator);
364 376
  free(de->de_title);
365 377
  free(de->de_ititle);
......
406 418
  channel_t *ch;
407 419
  uint32_t start, stop;
408 420
  int d;
421
  dvr_config_t *cfg;
409 422

  
410 423
  if(htsmsg_get_u32(c, "start", &start))
411 424
    return;
......
417 430
  if((ch = channel_find_by_name(s, 0, 0)) == NULL)
418 431
    return;
419 432

  
433
  s = htsmsg_get_str(c, "config_name");
434
  cfg = dvr_config_find_by_name_default(s);
435

  
420 436
  if((title = htsmsg_get_str(c, "title")) == NULL)
421 437
    return;
422 438

  
......
433 449

  
434 450
  de->de_start   = start;
435 451
  de->de_stop    = stop;
452
  de->de_config_name = strdup(cfg->dvr_config_name);
436 453
  de->de_creator = strdup(creator);
437 454
  de->de_title   = strdup(title);
438 455
  de->de_pri     = dvr_pri2val(htsmsg_get_str(c, "pri"));
439 456
  
440 457
  if(htsmsg_get_s32(c, "start_extra", &d))
441
    de->de_start_extra = dvr_extra_time_pre;
458
    de->de_start_extra = cfg->dvr_extra_time_pre;
442 459
  else
443 460
    de->de_start_extra = d;
444 461

  
445 462
  if(htsmsg_get_s32(c, "stop_extra", &d))
446
    de->de_stop_extra = dvr_extra_time_post;
463
    de->de_stop_extra = cfg->dvr_extra_time_post;
447 464
  else
448 465
    de->de_stop_extra = d;
449 466

  
......
519 536
  htsmsg_add_s32(m, "start_extra", de->de_start_extra);
520 537
  htsmsg_add_s32(m, "stop_extra", de->de_stop_extra);
521 538
  
539
  htsmsg_add_str(m, "config_name", de->de_config_name);
540

  
522 541
  htsmsg_add_str(m, "creator", de->de_creator);
523 542

  
524 543
  if(de->de_filename != NULL)
......
577 596
static void
578 597
dvr_stop_recording(dvr_entry_t *de, int stopcode)
579 598
{
599
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
600

  
580 601
  dvr_rec_unsubscribe(de, stopcode);
581 602

  
582 603
  de->de_sched_state = DVR_COMPLETED;
......
591 612
  dvr_entry_notify(de);
592 613

  
593 614
  gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, 
594
		 de->de_stop + dvr_retention_days * 86400);
615
		 de->de_stop + cfg->dvr_retention_days * 86400);
595 616
}
596 617

  
597 618

  
......
715 736
void
716 737
dvr_init(void)
717 738
{
718
  htsmsg_t *m;
739
  htsmsg_t *m, *l;
740
  htsmsg_field_t *f;
741
  const char *s;
719 742
  char buf[500];
720 743
  const char *homedir;
721 744
  struct stat st;
722 745
  uint32_t u32;
746
  dvr_config_t *cfg;
723 747

  
724 748
  dvr_iov_max = sysconf(_SC_IOV_MAX);
725 749

  
726 750
  /* Default settings */
727 751

  
728
  dvr_retention_days = 31;
729
  dvr_format       = strdup("matroska");
730
  dvr_file_postfix = strdup("mkv");
752
  LIST_INIT(&dvrconfigs);
753
  cfg = dvr_config_create("");
731 754

  
732 755
  /* Override settings with config */
733 756

  
734
  dvr_flags = DVR_TAG_FILES;
757
  l = hts_settings_load("dvr");
758
  if(l != NULL) {
759
    HTSMSG_FOREACH(f, l) {
760
      m = htsmsg_get_map_by_field(f);
761
      if(m == NULL)
762
        continue;
735 763

  
736
  if((m = hts_settings_load("dvr/config")) != NULL) {
764
      s = htsmsg_get_str(m, "config_name");
765
      cfg = dvr_config_find_by_name(s);
766
      if(cfg == NULL)
767
        cfg = dvr_config_create(s);
737 768

  
738
    htsmsg_get_s32(m, "pre-extra-time", &dvr_extra_time_pre);
739
    htsmsg_get_s32(m, "post-extra-time", &dvr_extra_time_post);
740
    htsmsg_get_u32(m, "retention-days", &dvr_retention_days);
741
    tvh_str_set(&dvr_storage, htsmsg_get_str(m, "storage"));
769
      htsmsg_get_s32(m, "pre-extra-time", &cfg->dvr_extra_time_pre);
770
      htsmsg_get_s32(m, "post-extra-time", &cfg->dvr_extra_time_post);
771
      htsmsg_get_u32(m, "retention-days", &cfg->dvr_retention_days);
772
      tvh_str_set(&cfg->dvr_storage, htsmsg_get_str(m, "storage"));
742 773

  
743
    if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
744
      dvr_flags |= DVR_DIR_PER_DAY;
774
      if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
775
        cfg->dvr_flags |= DVR_DIR_PER_DAY;
745 776

  
746
    if(!htsmsg_get_u32(m, "channel-dir", &u32) && u32)
747
      dvr_flags |= DVR_DIR_PER_CHANNEL;
777
      if(!htsmsg_get_u32(m, "channel-dir", &u32) && u32)
778
        cfg->dvr_flags |= DVR_DIR_PER_CHANNEL;
748 779

  
749
    if(!htsmsg_get_u32(m, "channel-in-title", &u32) && u32)
750
      dvr_flags |= DVR_CHANNEL_IN_TITLE;
780
      if(!htsmsg_get_u32(m, "channel-in-title", &u32) && u32)
781
        cfg->dvr_flags |= DVR_CHANNEL_IN_TITLE;
751 782

  
752
    if(!htsmsg_get_u32(m, "date-in-title", &u32) && u32)
753
      dvr_flags |= DVR_DATE_IN_TITLE;
783
      if(!htsmsg_get_u32(m, "date-in-title", &u32) && u32)
784
        cfg->dvr_flags |= DVR_DATE_IN_TITLE;
754 785

  
755
    if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
756
      dvr_flags |= DVR_TIME_IN_TITLE;
757
 
758
    if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
759
      dvr_flags |= DVR_WHITESPACE_IN_TITLE;
786
      if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
787
        cfg->dvr_flags |= DVR_TIME_IN_TITLE;
788
   
789
      if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
790
        cfg->dvr_flags |= DVR_WHITESPACE_IN_TITLE;
760 791

  
761
    if(!htsmsg_get_u32(m, "title-dir", &u32) && u32)
762
      dvr_flags |= DVR_DIR_PER_TITLE;
792
      if(!htsmsg_get_u32(m, "title-dir", &u32) && u32)
793
        cfg->dvr_flags |= DVR_DIR_PER_TITLE;
763 794

  
764
    if(!htsmsg_get_u32(m, "episode-in-title", &u32) && u32)
765
      dvr_flags |= DVR_EPISODE_IN_TITLE;
795
      if(!htsmsg_get_u32(m, "episode-in-title", &u32) && u32)
796
        cfg->dvr_flags |= DVR_EPISODE_IN_TITLE;
766 797

  
767
    if(!htsmsg_get_u32(m, "tag-files", &u32) && !u32)
768
      dvr_flags &= ~DVR_TAG_FILES;
769
   
770
    tvh_str_set(&dvr_postproc, htsmsg_get_str(m, "postproc"));
798
      if(!htsmsg_get_u32(m, "tag-files", &u32) && !u32)
799
        cfg->dvr_flags &= ~DVR_TAG_FILES;
800
     
801
      tvh_str_set(&cfg->dvr_postproc, htsmsg_get_str(m, "postproc"));
802
    }
771 803

  
772
    htsmsg_destroy(m);
804
    htsmsg_destroy(l);
773 805
  }
774 806

  
775
  if(dvr_storage == NULL) {
776
    /* Try to figure out a good place to put them videos */
777

  
778
    homedir = getenv("HOME");
779

  
780
    if(homedir != NULL) {
781
      snprintf(buf, sizeof(buf), "%s/Videos", homedir);
782
      if(stat(buf, &st) == 0 && S_ISDIR(st.st_mode))
783
	dvr_storage = strdup(buf);
784
      
785
      else if(stat(homedir, &st) == 0 && S_ISDIR(st.st_mode))
786
	dvr_storage = strdup(homedir);
787
      else
788
	dvr_storage = strdup(getcwd(buf, sizeof(buf)));
807
  LIST_FOREACH(cfg, &dvrconfigs, config_link) {
808
    if(cfg->dvr_storage == NULL || !strlen(cfg->dvr_storage)) {
809
      /* Try to figure out a good place to put them videos */
810

  
811
      homedir = getenv("HOME");
812

  
813
      if(homedir != NULL) {
814
        snprintf(buf, sizeof(buf), "%s/Videos", homedir);
815
        if(stat(buf, &st) == 0 && S_ISDIR(st.st_mode))
816
          cfg->dvr_storage = strdup(buf);
817
        
818
        else if(stat(homedir, &st) == 0 && S_ISDIR(st.st_mode))
819
          cfg->dvr_storage = strdup(homedir);
820
        else
821
          cfg->dvr_storage = strdup(getcwd(buf, sizeof(buf)));
822
      }
823

  
824
      tvhlog(LOG_WARNING, "dvr",
825
             "Output directory for video recording is not yet configured "
826
             "for DVR configuration \"%s\". "
827
             "Defaulting to to \"%s\". "
828
             "This can be changed from the web user interface.",
829
             cfg->dvr_config_name, cfg->dvr_storage);
789 830
    }
790

  
791
    tvhlog(LOG_WARNING, "dvr",
792
	   "Output directory for video recording is not yet configured. "
793
	   "Defaulting to to \"%s\". "
794
	   "This can be changed from the web user interface.",
795
	   dvr_storage);
796 831
  }
797 832

  
798 833
  dvr_autorec_init();
......
801 836
}
802 837

  
803 838
/**
839
 * find a dvr config by name, return NULL if not found
840
 */
841
dvr_config_t *
842
dvr_config_find_by_name(const char *name)
843
{
844
  dvr_config_t *cfg;
845

  
846
  if (name == NULL)
847
    name = "";
848

  
849
  LIST_FOREACH(cfg, &dvrconfigs, config_link)
850
    if (!strcmp(name, cfg->dvr_config_name))
851
      return cfg;
852

  
853
  return NULL;
854
}
855

  
856
/**
857
 * find a dvr config by name, return the default config if not found
858
 */
859
dvr_config_t *
860
dvr_config_find_by_name_default(const char *name)
861
{
862
  dvr_config_t *cfg;
863

  
864
  cfg = dvr_config_find_by_name(name);
865

  
866
  if (cfg == NULL) {
867
    tvhlog(LOG_WARNING, "dvr", "Configuration '%s' not found", name);
868
    cfg = dvr_config_find_by_name("");
869
  }
870

  
871
  if (cfg == NULL) {
872
    cfg = dvr_config_create("");
873
  }
874

  
875
  return cfg;
876
}
877

  
878
/**
879
 * create a new named dvr config; the caller is responsible
880
 * to avoid duplicates
881
 */
882
dvr_config_t *
883
dvr_config_create(const char *name)
884
{
885
  dvr_config_t *cfg;
886

  
887
  if (name == NULL)
888
    name = "";
889

  
890
  tvhlog(LOG_INFO, "dvr", "Creating new configuration '%s'", name);
891

  
892
  cfg = calloc(1, sizeof(dvr_config_t));
893
  cfg->dvr_config_name = strdup(name);
894
  cfg->dvr_retention_days = 31;
895
  cfg->dvr_format = strdup("matroska");
896
  cfg->dvr_file_postfix = strdup("mkv");
897
  cfg->dvr_flags = DVR_TAG_FILES;
898

  
899
  LIST_INSERT_HEAD(&dvrconfigs, cfg, config_link);
900

  
901
  return LIST_FIRST(&dvrconfigs);
902
}
903

  
904
/**
905
 *
906
 */
907
void 
908
dvr_config_delete(const char *name)
909
{
910
  dvr_config_t *cfg;
911

  
912
  if (name == NULL || strlen(name) == 0) {
913
    tvhlog(LOG_WARNING,"dvr","Attempt to delete default config ignored");
914
    return;
915
  }
916

  
917
  cfg = dvr_config_find_by_name(name);
918
  if (cfg != NULL) {
919
    tvhlog(LOG_INFO, "dvr", "Deleting configuration '%s'", 
920
        cfg->dvr_config_name);
921
    hts_settings_remove("dvr/config%s", cfg->dvr_config_name);
922
    LIST_REMOVE(cfg, config_link);
923
    dvrconfig_changed();
924
  }
925
}
926

  
927
/**
804 928
 *
805 929
 */
806 930
static void
807
dvr_save(void)
931
dvr_save(dvr_config_t *cfg)
808 932
{
809 933
  htsmsg_t *m = htsmsg_create_map();
810
  htsmsg_add_str(m, "storage", dvr_storage);
811
  htsmsg_add_u32(m, "retention-days", dvr_retention_days);
812
  htsmsg_add_u32(m, "pre-extra-time", dvr_extra_time_pre);
813
  htsmsg_add_u32(m, "post-extra-time", dvr_extra_time_post);
814
  htsmsg_add_u32(m, "day-dir",          !!(dvr_flags & DVR_DIR_PER_DAY));
815
  htsmsg_add_u32(m, "channel-dir",      !!(dvr_flags & DVR_DIR_PER_CHANNEL));
816
  htsmsg_add_u32(m, "channel-in-title", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
817
  htsmsg_add_u32(m, "date-in-title",    !!(dvr_flags & DVR_DATE_IN_TITLE));
818
  htsmsg_add_u32(m, "time-in-title",    !!(dvr_flags & DVR_TIME_IN_TITLE));
819
  htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
820
  htsmsg_add_u32(m, "title-dir", !!(dvr_flags & DVR_DIR_PER_TITLE));
821
  htsmsg_add_u32(m, "episode-in-title", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
822
  htsmsg_add_u32(m, "tag-files", !!(dvr_flags & DVR_TAG_FILES));
823
  if(dvr_postproc != NULL)
824
    htsmsg_add_str(m, "postproc", dvr_postproc);
825

  
826
  hts_settings_save(m, "dvr/config");
934
  if (cfg->dvr_config_name != NULL && strlen(cfg->dvr_config_name) != 0)
935
    htsmsg_add_str(m, "config_name", cfg->dvr_config_name);
936
  htsmsg_add_str(m, "storage", cfg->dvr_storage);
937
  htsmsg_add_u32(m, "retention-days", cfg->dvr_retention_days);
938
  htsmsg_add_u32(m, "pre-extra-time", cfg->dvr_extra_time_pre);
939
  htsmsg_add_u32(m, "post-extra-time", cfg->dvr_extra_time_post);
940
  htsmsg_add_u32(m, "day-dir",          !!(cfg->dvr_flags & DVR_DIR_PER_DAY));
941
  htsmsg_add_u32(m, "channel-dir",      !!(cfg->dvr_flags & DVR_DIR_PER_CHANNEL));
942
  htsmsg_add_u32(m, "channel-in-title", !!(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE));
943
  htsmsg_add_u32(m, "date-in-title",    !!(cfg->dvr_flags & DVR_DATE_IN_TITLE));
944
  htsmsg_add_u32(m, "time-in-title",    !!(cfg->dvr_flags & DVR_TIME_IN_TITLE));
945
  htsmsg_add_u32(m, "whitespace-in-title", !!(cfg->dvr_flags & DVR_WHITESPACE_IN_TITLE));
946
  htsmsg_add_u32(m, "title-dir", !!(cfg->dvr_flags & DVR_DIR_PER_TITLE));
947
  htsmsg_add_u32(m, "episode-in-title", !!(cfg->dvr_flags & DVR_EPISODE_IN_TITLE));
948
  htsmsg_add_u32(m, "tag-files", !!(cfg->dvr_flags & DVR_TAG_FILES));
949
  if(cfg->dvr_postproc != NULL)
950
    htsmsg_add_str(m, "postproc", cfg->dvr_postproc);
951

  
952
  hts_settings_save(m, "dvr/config%s", cfg->dvr_config_name);
827 953
  htsmsg_destroy(m);
954

  
955
  dvrconfig_changed();
828 956
}
829 957

  
830 958
/**
831 959
 *
832 960
 */
833 961
void
834
dvr_storage_set(const char *storage)
962
dvr_storage_set(dvr_config_t *cfg, const char *storage)
835 963
{
836
  if(!strcmp(dvr_storage, storage))
964
  if(cfg->dvr_storage != NULL && !strcmp(cfg->dvr_storage, storage))
837 965
    return;
838 966

  
839
  tvh_str_set(&dvr_storage, storage);
840
  dvr_save();
967
  tvh_str_set(&cfg->dvr_storage, storage);
968
  dvr_save(cfg);
841 969
}
842 970

  
843 971
/**
844 972
 *
845 973
 */
846 974
void
847
dvr_postproc_set(const char *postproc)
975
dvr_postproc_set(dvr_config_t *cfg, const char *postproc)
848 976
{
849
  if(dvr_postproc != NULL && !strcmp(dvr_postproc, postproc))
977
  if(cfg->dvr_postproc != NULL && !strcmp(cfg->dvr_postproc, postproc))
850 978
    return;
851 979

  
852
  tvh_str_set(&dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
853
  dvr_save();
980
  tvh_str_set(&cfg->dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
981
  dvr_save(cfg);
854 982
}
855 983

  
856 984

  
......
858 986
 *
859 987
 */
860 988
void
861
dvr_retention_set(int days)
989
dvr_retention_set(dvr_config_t *cfg, int days)
862 990
{
863 991
  dvr_entry_t *de;
864
  if(days < 1 || dvr_retention_days == days)
992
  if(days < 1 || cfg->dvr_retention_days == days)
865 993
    return;
866 994

  
867
  dvr_retention_days = days;
995
  cfg->dvr_retention_days = days;
868 996

  
869 997
  /* Also, rearm all timres */
870 998

  
871 999
  LIST_FOREACH(de, &dvrentries, de_global_link)
872 1000
    if(de->de_sched_state == DVR_COMPLETED)
873 1001
      gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, 
874
		     de->de_stop + dvr_retention_days * 86400);
875
  dvr_save();
1002
		     de->de_stop + cfg->dvr_retention_days * 86400);
1003
  dvr_save(cfg);
876 1004
}
877 1005

  
878 1006

  
......
880 1008
 *
881 1009
 */
882 1010
void
883
dvr_flags_set(int flags)
1011
dvr_flags_set(dvr_config_t *cfg, int flags)
884 1012
{
885
  if(dvr_flags == flags)
1013
  if(cfg->dvr_flags == flags)
886 1014
    return;
887 1015

  
888
  dvr_flags = flags;
889
  dvr_save();
1016
  cfg->dvr_flags = flags;
1017
  dvr_save(cfg);
890 1018
}
891 1019

  
892 1020

  
......
894 1022
 *
895 1023
 */
896 1024
void
897
dvr_extra_time_pre_set(int d)
1025
dvr_extra_time_pre_set(dvr_config_t *cfg, int d)
898 1026
{
899
  if(dvr_extra_time_pre == d)
1027
  if(cfg->dvr_extra_time_pre == d)
900 1028
    return;
901
  dvr_extra_time_pre = d;
902
  dvr_save();
1029

  
1030
  cfg->dvr_extra_time_pre = d;
1031
  dvr_save(cfg);
903 1032
}
904 1033

  
905 1034

  
......
907 1036
 *
908 1037
 */
909 1038
void
910
dvr_extra_time_post_set(int d)
1039
dvr_extra_time_post_set(dvr_config_t *cfg, int d)
911 1040
{
912
  if(dvr_extra_time_post == d)
1041
  if(cfg->dvr_extra_time_post == d)
913 1042
    return;
914
  dvr_extra_time_post = d;
915
  dvr_save();
1043

  
1044
  cfg->dvr_extra_time_post = d;
1045
  dvr_save(cfg);
916 1046
}
917 1047

  
918 1048

  
tvheadend/src/dvr/dvr_rec.c
40 40
 *
41 41
 */
42 42
static void *dvr_thread(void *aux);
43
static void dvr_spawn_postproc(dvr_entry_t *de);
43
static void dvr_spawn_postproc(dvr_entry_t *de, const char *dvr_postproc);
44 44
static void dvr_thread_epilog(dvr_entry_t *de);
45 45

  
46 46

  
......
157 157
 * Replace various chars with a dash
158 158
 */
159 159
static void
160
cleanupfilename(char *s)
160
cleanupfilename(char *s, int dvr_flags)
161 161
{
162 162
  int i, len = strlen(s);
163 163
  for(i = 0; i < len; i++) { 
......
186 186
  struct stat st;
187 187
  char *filename;
188 188
  struct tm tm;
189
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
189 190

  
190 191
  filename = strdup(de->de_ititle);
191
  cleanupfilename(filename);
192
  cleanupfilename(filename,cfg->dvr_flags);
192 193

  
193
  snprintf(path, sizeof(path), "%s", dvr_storage);
194
  snprintf(path, sizeof(path), "%s", cfg->dvr_storage);
194 195

  
195 196
  /* Append per-day directory */
196 197

  
197
  if(dvr_flags & DVR_DIR_PER_DAY) {
198
  if(cfg->dvr_flags & DVR_DIR_PER_DAY) {
198 199
    localtime_r(&de->de_start, &tm);
199 200
    strftime(fullname, sizeof(fullname), "%F", &tm);
200
    cleanupfilename(fullname);
201
    cleanupfilename(fullname,cfg->dvr_flags);
201 202
    snprintf(path + strlen(path), sizeof(path) - strlen(path), 
202 203
	     "/%s", fullname);
203 204
  }
204 205

  
205 206
  /* Append per-channel directory */
206 207

  
207
  if(dvr_flags & DVR_DIR_PER_CHANNEL) {
208
  if(cfg->dvr_flags & DVR_DIR_PER_CHANNEL) {
208 209

  
209 210
    char *chname = strdup(de->de_channel->ch_name);
210
    cleanupfilename(chname);
211
    cleanupfilename(chname,cfg->dvr_flags);
211 212
    snprintf(path + strlen(path), sizeof(path) - strlen(path), 
212 213
	     "/%s", chname);
213 214
    free(chname);
......
215 216

  
216 217
  /* Append per-title directory */
217 218

  
218
  if(dvr_flags & DVR_DIR_PER_TITLE) {
219
  if(cfg->dvr_flags & DVR_DIR_PER_TITLE) {
219 220

  
220 221
    char *title = strdup(de->de_title);
221
    cleanupfilename(title);
222
    cleanupfilename(title,cfg->dvr_flags);
222 223
    snprintf(path + strlen(path), sizeof(path) - strlen(path), 
223 224
	     "/%s", title);
224 225
    free(title);
......
233 234
  /* Construct final name */
234 235
  
235 236
  snprintf(fullname, sizeof(fullname), "%s/%s.%s",
236
	   path, filename, dvr_file_postfix);
237
	   path, filename, cfg->dvr_file_postfix);
237 238

  
238 239
  while(1) {
239 240
    if(stat(fullname, &st) == -1) {
......
248 249
    tally++;
249 250

  
250 251
    snprintf(fullname, sizeof(fullname), "%s/%s-%d.%s",
251
	     path, filename, tally, dvr_file_postfix);
252
	     path, filename, tally, cfg->dvr_file_postfix);
252 253
  }
253 254

  
254 255
  tvh_str_set(&de->de_filename, fullname);
......
301 302
  const source_info_t *si = &ss->ss_si;
302 303
  const streaming_start_component_t *ssc;
303 304
  int i;
305
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
304 306

  
305 307
  if(pvr_generate_filename(de) != 0) {
306 308
    dvr_rec_fatal_error(de, "Unable to create directories");
......
308 310
  }
309 311

  
310 312
  de->de_mkmux = mk_mux_create(de->de_filename, ss, de, 
311
			       !!(dvr_flags & DVR_TAG_FILES));
313
			       !!(cfg->dvr_flags & DVR_TAG_FILES));
312 314

  
313 315
  if(de->de_mkmux == NULL) {
314 316
    dvr_rec_fatal_error(de, "Unable to open file");
......
497 499
 *
498 500
 */
499 501
static void
500
dvr_spawn_postproc(dvr_entry_t *de)
502
dvr_spawn_postproc(dvr_entry_t *de, const char *dvr_postproc)
501 503
{
502 504
  char *fmap[256];
503 505
  char **args;
......
553 555
  mk_mux_close(de->de_mkmux);
554 556
  de->de_mkmux = NULL;
555 557

  
556
  if(dvr_postproc)
557
    dvr_spawn_postproc(de);
558
  dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
559
  if(cfg->dvr_postproc)
560
    dvr_spawn_postproc(de,cfg->dvr_postproc);
558 561
}
tvheadend/src/htsp.c
493 493
  event_t *e;
494 494
  dvr_entry_t *de;
495 495
  dvr_entry_sched_state_t dvr_status;
496
  const char *dvr_config_name;
496 497
    
497 498
  if(htsmsg_get_u32(in, "eventId", &eventid))
498 499
    return htsp_error("Missing argument 'eventId'");
499 500
  
500 501
  if((e = epg_event_find_by_id(eventid)) == NULL)
501 502
    return htsp_error("Event does not exist");
503

  
504
  if((dvr_config_name = htsmsg_get_str(in, "configName")) == NULL)
505
    dvr_config_name = "";
502 506
  
503 507
  //create the dvr entry
504
  de = dvr_entry_create_by_event(e, 
508
  de = dvr_entry_create_by_event(dvr_config_name,e, 
505 509
				 htsp->htsp_username ? 
506 510
				 htsp->htsp_username : "anonymous",
507 511
				 NULL, DVR_PRIO_NORMAL);
......
698 702
{
699 703
  htsmsg_t *out;
700 704
  struct statvfs diskdata;
705
  dvr_config_t *cfg = dvr_config_find_by_name_default("");
701 706

  
702
  if(statvfs(dvr_storage,&diskdata) == -1)
707
  if(statvfs(cfg->dvr_storage,&diskdata) == -1)
703 708
    return htsp_error("Unable to stat path");
704 709
  
705 710
  out = htsmsg_create_map();
tvheadend/src/tvhead.h
104 104
LIST_HEAD(channel_list, channel);
105 105
LIST_HEAD(event_list, event);
106 106
RB_HEAD(event_tree, event);
107
LIST_HEAD(dvr_config_list, dvr_config);
107 108
LIST_HEAD(dvr_entry_list, dvr_entry);
108 109
TAILQ_HEAD(ref_update_queue, ref_update);
109 110
LIST_HEAD(th_transport_list, th_transport);
tvheadend/src/webui/extjs.c
568 568

  
569 569
  pthread_mutex_lock(&global_lock);
570 570

  
571
  if(!strcmp(op, "listTags")) {
571
  if(op != NULL && !strcmp(op, "listTags")) {
572 572

  
573 573
    out = htsmsg_create_map();
574 574
    array = htsmsg_create_list();
......
603 603
 *
604 604
 */
605 605
static int
606
extjs_confignames(http_connection_t *hc, const char *remain, void *opaque)
607
{
608
  htsbuf_queue_t *hq = &hc->hc_reply;
609
  const char *op = http_arg_get(&hc->hc_req_args, "op");
610
  htsmsg_t *out, *array, *e;
611
  dvr_config_t *cfg;
612

  
613
  pthread_mutex_lock(&global_lock);
614

  
615
  if(op != NULL && !strcmp(op, "list")) {
616

  
617
    out = htsmsg_create_map();
618
    array = htsmsg_create_list();
619

  
620
    LIST_FOREACH(cfg, &dvrconfigs, config_link) {
621
      e = htsmsg_create_map();
622
      htsmsg_add_str(e, "identifier", cfg->dvr_config_name);
623
      if (strlen(cfg->dvr_config_name) == 0)
624
        htsmsg_add_str(e, "name", "(default)");
625
      else
626
        htsmsg_add_str(e, "name", cfg->dvr_config_name);
627
      htsmsg_add_msg(array, NULL, e);
628
    }
629

  
630
    htsmsg_add_msg(out, "entries", array);
631

  
632
  } else {
633
    pthread_mutex_unlock(&global_lock);
634
    return HTTP_STATUS_BAD_REQUEST;
635
  }
636

  
637
  pthread_mutex_unlock(&global_lock);
638

  
639
  htsmsg_json_serialize(out, hq, 0);
640
  htsmsg_destroy(out);
641
  http_output_content(hc, "text/x-json; charset=UTF-8");
642
  return 0;
643

  
644
}
645

  
646
/**
647
 *
648
 */
649
static int
606 650
extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
607 651
{
608 652
  htsbuf_queue_t *hq = &hc->hc_reply;
......
713 757
  dvr_entry_t *de;
714 758
  const char *s;
715 759
  int flags = 0;
760
  dvr_config_t *cfg;
716 761

  
717 762
  if(op == NULL)
718 763
    op = "loadSettings";
......
725 770
  }
726 771

  
727 772
  if(!strcmp(op, "recordEvent")) {
728
    s = http_arg_get(&hc->hc_req_args, "eventId");
729 773

  
774
    const char *config_name = http_arg_get(&hc->hc_req_args, "config_name");
775

  
776
    s = http_arg_get(&hc->hc_req_args, "eventId");
730 777
    if((e = epg_event_find_by_id(atoi(s))) == NULL) {
731 778
      pthread_mutex_unlock(&global_lock);
732 779
      return HTTP_STATUS_BAD_REQUEST;
733 780
    }
734 781

  
735
    dvr_entry_create_by_event(e, hc->hc_representative, NULL, DVR_PRIO_NORMAL);
782
    dvr_entry_create_by_event(config_name,
783
                              e, hc->hc_representative, NULL, DVR_PRIO_NORMAL);
736 784

  
737 785
    out = htsmsg_create_map();
738 786
    htsmsg_add_u32(out, "success", 1);
......
751 799

  
752 800
  } else if(!strcmp(op, "createEntry")) {
753 801

  
802
    const char *config_name = http_arg_get(&hc->hc_req_args, "config_name");
754 803
    const char *title    = http_arg_get(&hc->hc_req_args, "title");
755 804
    const char *datestr  = http_arg_get(&hc->hc_req_args, "date");
756 805
    const char *startstr = http_arg_get(&hc->hc_req_args, "starttime");
......
787 836
    if(stop < start)
788 837
      stop += 86400;
789 838

  
790
    dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative, 
839
    dvr_entry_create(config_name,
840
                     ch, start, stop, title, NULL, hc->hc_representative, 
791 841
		     NULL, NULL, 0, dvr_pri2val(pri));
792 842

  
793 843
    out = htsmsg_create_map();
......
798 848

  
799 849
    
800 850

  
801
    dvr_autorec_add(http_arg_get(&hc->hc_req_args, "title"),
851
    dvr_autorec_add(http_arg_get(&hc->hc_req_args, "config_name"),
852
                    http_arg_get(&hc->hc_req_args, "title"),
802 853
		    http_arg_get(&hc->hc_req_args, "channel"),
803 854
		    http_arg_get(&hc->hc_req_args, "tag"),
804 855
		    cgrp ? epg_content_group_find_by_name(cgrp) : 0,
......
809 860

  
810 861
  } else if(!strcmp(op, "loadSettings")) {
811 862

  
863
    s = http_arg_get(&hc->hc_req_args, "config_name");
864
    if (s == NULL)
865
      s = "";
866
    cfg = dvr_config_find_by_name_default(s);
867

  
812 868
    r = htsmsg_create_map();
813
    htsmsg_add_str(r, "storage", dvr_storage);
814
    if(dvr_postproc != NULL)
815
      htsmsg_add_str(r, "postproc", dvr_postproc);
816
    htsmsg_add_u32(r, "retention", dvr_retention_days);
817
    htsmsg_add_u32(r, "preExtraTime", dvr_extra_time_pre);
818
    htsmsg_add_u32(r, "postExtraTime", dvr_extra_time_post);
819
    htsmsg_add_u32(r, "dayDirs",        !!(dvr_flags & DVR_DIR_PER_DAY));
820
    htsmsg_add_u32(r, "channelDirs",    !!(dvr_flags & DVR_DIR_PER_CHANNEL));
821
    htsmsg_add_u32(r, "channelInTitle", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
822
    htsmsg_add_u32(r, "dateInTitle",    !!(dvr_flags & DVR_DATE_IN_TITLE));
823
    htsmsg_add_u32(r, "timeInTitle",    !!(dvr_flags & DVR_TIME_IN_TITLE));
824
    htsmsg_add_u32(r, "whitespaceInTitle", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
825
    htsmsg_add_u32(r, "titleDirs", !!(dvr_flags & DVR_DIR_PER_TITLE));
826
    htsmsg_add_u32(r, "episodeInTitle", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
827
    htsmsg_add_u32(r, "cleanTitle", !!(dvr_flags & DVR_CLEAN_TITLE));
828
    htsmsg_add_u32(r, "tagFiles", !!(dvr_flags & DVR_TAG_FILES));
869
    htsmsg_add_str(r, "storage", cfg->dvr_storage);
870
    if(cfg->dvr_postproc != NULL)
871
      htsmsg_add_str(r, "postproc", cfg->dvr_postproc);
872
    htsmsg_add_u32(r, "retention", cfg->dvr_retention_days);
873
    htsmsg_add_u32(r, "preExtraTime", cfg->dvr_extra_time_pre);
874
    htsmsg_add_u32(r, "postExtraTime", cfg->dvr_extra_time_post);
875
    htsmsg_add_u32(r, "dayDirs",        !!(cfg->dvr_flags & DVR_DIR_PER_DAY));
876
    htsmsg_add_u32(r, "channelDirs",    !!(cfg->dvr_flags & DVR_DIR_PER_CHANNEL));
877
    htsmsg_add_u32(r, "channelInTitle", !!(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE));
878
    htsmsg_add_u32(r, "dateInTitle",    !!(cfg->dvr_flags & DVR_DATE_IN_TITLE));
879
    htsmsg_add_u32(r, "timeInTitle",    !!(cfg->dvr_flags & DVR_TIME_IN_TITLE));
880
    htsmsg_add_u32(r, "whitespaceInTitle", !!(cfg->dvr_flags & DVR_WHITESPACE_IN_TITLE));
881
    htsmsg_add_u32(r, "titleDirs", !!(cfg->dvr_flags & DVR_DIR_PER_TITLE));
882
    htsmsg_add_u32(r, "episodeInTitle", !!(cfg->dvr_flags & DVR_EPISODE_IN_TITLE));
883
    htsmsg_add_u32(r, "cleanTitle", !!(cfg->dvr_flags & DVR_CLEAN_TITLE));
884
    htsmsg_add_u32(r, "tagFiles", !!(cfg->dvr_flags & DVR_TAG_FILES));
829 885

  
830 886
    out = json_single_record(r, "dvrSettings");
831 887

  
832 888
  } else if(!strcmp(op, "saveSettings")) {
833 889

  
890
    s = http_arg_get(&hc->hc_req_args, "config_name");
891
    cfg = dvr_config_find_by_name(s);
892
    if (cfg == NULL)
893
      cfg = dvr_config_create(s);
894

  
895
    tvhlog(LOG_INFO,"dvr","Saving configuration '%s'", cfg->dvr_config_name);
896

  
834 897
    if((s = http_arg_get(&hc->hc_req_args, "storage")) != NULL)
835
      dvr_storage_set(s);
898
      dvr_storage_set(cfg,s);
836 899
    
837 900
    if((s = http_arg_get(&hc->hc_req_args, "postproc")) != NULL)
838
      dvr_postproc_set(s);
901
      dvr_postproc_set(cfg,s);
839 902

  
840 903
    if((s = http_arg_get(&hc->hc_req_args, "retention")) != NULL)
841
      dvr_retention_set(atoi(s));
904
      dvr_retention_set(cfg,atoi(s));
842 905

  
843 906
   if((s = http_arg_get(&hc->hc_req_args, "preExtraTime")) != NULL)
844
     dvr_extra_time_pre_set(atoi(s));
907
     dvr_extra_time_pre_set(cfg,atoi(s));
845 908

  
846 909
   if((s = http_arg_get(&hc->hc_req_args, "postExtraTime")) != NULL)
847
     dvr_extra_time_post_set(atoi(s));
910
     dvr_extra_time_post_set(cfg,atoi(s));
848 911

  
849 912
    if(http_arg_get(&hc->hc_req_args, "dayDirs") != NULL)
850 913
      flags |= DVR_DIR_PER_DAY;
......
867 930
    if(http_arg_get(&hc->hc_req_args, "tagFiles") != NULL)
868 931
      flags |= DVR_TAG_FILES;
869 932

  
870
    dvr_flags_set(flags);
933
    dvr_flags_set(cfg,flags);
934

  
935
    out = htsmsg_create_map();
936
    htsmsg_add_u32(out, "success", 1);
937

  
938
  } else if(!strcmp(op, "deleteSettings")) {
939

  
940
    s = http_arg_get(&hc->hc_req_args, "config_name");
941
    dvr_config_delete(s);
871 942

  
872 943
    out = htsmsg_create_map();
873 944
    htsmsg_add_u32(out, "success", 1);
......
941 1012
	htsmsg_add_str(m, "chicon", de->de_channel->ch_icon);
942 1013
    }
943 1014

  
1015
    htsmsg_add_str(m, "config_name", de->de_config_name);
1016

  
944 1017
    if(de->de_title != NULL)
945 1018
      htsmsg_add_str(m, "title", de->de_title);
946 1019

  
......
1401 1474
  http_path_add("/channels",    NULL, extjs_channels,    ACCESS_WEB_INTERFACE);
1402 1475
  http_path_add("/xmltv",       NULL, extjs_xmltv,       ACCESS_WEB_INTERFACE);
1403 1476
  http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
1477
  http_path_add("/confignames", NULL, extjs_confignames, ACCESS_WEB_INTERFACE);
1404 1478
  http_path_add("/epg",         NULL, extjs_epg,         ACCESS_WEB_INTERFACE);
1405 1479
  http_path_add("/dvr",         NULL, extjs_dvr,         ACCESS_WEB_INTERFACE);
1406 1480
  http_path_add("/dvrlist",     NULL, extjs_dvrlist,     ACCESS_WEB_INTERFACE);
tvheadend/src/webui/simpleui.c
210 210
  de = dvr_entry_find_by_event(e);
211 211

  
212 212
  if((http_arg_get(&hc->hc_req_args, "rec")) != NULL) {
213
    de = dvr_entry_create_by_event(e, hc->hc_username ?: "anonymous", NULL,
213
    de = dvr_entry_create_by_event("", e, hc->hc_username ?: "anonymous", NULL,
214 214
				   DVR_PRIO_NORMAL);
215 215
  } else if(de != NULL && (http_arg_get(&hc->hc_req_args, "cancel")) != NULL) {
216 216
    de = dvr_entry_cancel(de);
tvheadend/src/webui/static/app/comet.js
12 12
	channeltags: true,
13 13
	autorec: true,
14 14
	dvrdb: true,
15
        dvrconfig: true,
15 16
	channels: true
16 17
    });
17 18
}, Ext.util.Observable);
tvheadend/src/webui/static/app/dvr.js
28 28
});
29 29

  
30 30
/**
31
 * Configuration names
32
 */
33
tvheadend.configNames = new Ext.data.JsonStore({
34
    autoLoad:true,
35
    root:'entries',
36
    fields: ['identifier','name'],
37
    id: 'identifier',
38
    url:'confignames',
39
    baseParams: {
40
	op: 'list'
41
    }
42
});
43

  
44
tvheadend.configNames.setDefaultSort('name', 'ASC');
45

  
46
tvheadend.comet.on('dvrconfig', function(m) {
47
    if(m.reload != null)
48
        tvheadend.configNames.reload();
49
});
50

  
51

  
52
/**
31 53
 *
32 54
 */
33 55
tvheadend.dvrDetails = function(entry) {
......
190 212
	    hidden:true,
191 213
	    dataIndex: 'creator'
192 214
	},{
215
            width: 200,
216
            id:'config_name',
217
            header: "DVR Configuration",
218
            renderer: function(value, metadata, record, row, col, store) {
219
		if (!value) {
220
		    return '<span class="tvh-grid-unset">(default)</span>';
221
		} else {
222
		    return value;
223
		}
224
	    },
225
            dataIndex: 'config_name'
226
        },{
193 227
	    width: 200,
194 228
	    id:'status',
195 229
	    header: "Status",
......
267 301
		    allowBlank: false,
268 302
		    fieldLabel: 'Title',
269 303
		    name: 'title'
270
		}
304
		},
305
		new Ext.form.ComboBox({
306
		    store: tvheadend.configNames,
307
		    triggerAction: 'all',
308
		    mode: 'local',
309
		    fieldLabel: 'DVR Configuration',
310
                    valueField: 'identifier',
311
                    displayField: 'name',
312
		    name: 'config_name',
313
                    emptyText: '(default)',
314
                    value: '',
315
                    editable: false
316
		})
271 317
	    ],
272 318
	    buttons: [{
273 319
		text: 'Create',
......
285 331
            items: panel
286 332
	});
287 333
	win.show();	
334
		new Ext.form.ComboBox({
335
		    store: tvheadend.configNames,
336
		    triggerAction: 'all',
337
		    mode: 'local',
338
		    fieldLabel: 'DVR Configuration',
339
                    valueField: 'identifier',
340
                    displayField: 'name',
341
		    name: 'config_name',
342
                    emptyText: '(default)',
343
                    value: '',
344
                    editable: false
345
		})
288 346
    };
289 347

  
290 348

  
......
448 506
                valueField: 'identifier',
449 507
                displayField: 'name'
450 508
	    })
509
        },{
510
	    header: "DVR Configuration",
511
	    dataIndex: 'config_name',
512
            renderer: function(value, metadata, record, row, col, store) {
513
		if (!value) {
514
		    return '<span class="tvh-grid-unset">(default)</span>';
515
		} else {
516
		    return value;
517
		}
518
	    },
519
            editor: new Ext.form.ComboBox({
520
                store: tvheadend.configNames,
521
                triggerAction: 'all',
522
                mode: 'local',
523
                valueField: 'identifier',
524
                displayField: 'name',
525
                name: 'config_name',
526
                emptyText: '(default)',
527
                editable: false
528
            })
451 529
	},{
452 530
	    header: "Created by",
453 531
	    dataIndex: 'creator',
......
484 562
	    {name: 'chicon'},
485 563
            {name: 'start', type: 'date', dateFormat: 'U' /* unix time */},
486 564
            {name: 'end', type: 'date', dateFormat: 'U' /* unix time */},
565
            {name: 'config_name'},
487 566
	    {name: 'status'},
488 567
	    {name: 'schedstate'},
489 568
	    {name: 'creator'},
......
522 601
    
523 602
    tvheadend.autorecRecord = Ext.data.Record.create([
524 603
	'enabled','title','channel','tag','creator','contentgrp','comment',
525
	'weekdays', 'pri', 'approx_time'
604
	'weekdays', 'pri', 'approx_time', 'config_name'
526 605
    ]);
527 606
    
528 607

  
......
568 647
	'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 
569 648
	'titleDirs', 'episodeInTitle', 'cleanTitle', 'tagFiles']);
570 649

  
650
    var confcombo = new Ext.form.ComboBox({
651
        store: tvheadend.configNames,
652
        triggerAction: 'all',
653
        mode: 'local',
654
        displayField: 'name',
655
        name: 'config_name',
656
        emptyText: '(default)',
657
        value: '',
658
        editable: true
659
    });
660

  
661
    var delButton = new Ext.Toolbar.Button({
662
        tooltip: 'Delete named configuration',
663
        iconCls:'remove',
664
        text: "Delete configuration",
665
        handler: deleteConfiguration,
666
        disabled: true
667
    });
668

  
571 669
    var confpanel = new Ext.FormPanel({
572 670
	title:'Digital Video Recorder',
573 671
	iconCls: 'drive',
......
633 731
	    fieldLabel: 'Post-processor command',
634 732
	    name: 'postproc'
635 733
        }],
636
	tbar: [{
637
	    tooltip: 'Save changes made to channel configuration below',
734
	tbar: [confcombo, {
735
	    tooltip: 'Save changes made to dvr configuration below',
638 736
	    iconCls:'save',
639 737
	    text: "Save configuration",
640 738
	    handler: saveChanges
641
	}, '->', {
739
	}, delButton, '->', {
642 740
	    text: 'Help',
643 741
	    handler: function() {
644 742
		new tvheadend.help('DVR configuration', 
645 743
				   'config_dvr.html');
646 744
	    }
647 745
	}]
648
	
649 746
    });
650

  
651
    confpanel.on('render', function() {
747
    
748
    function loadConfig() {
652 749
	confpanel.getForm().load({
653 750
	    url:'dvr', 
654
	    params:{'op':'loadSettings'},
751
	    params:{'op':'loadSettings','config_name':confcombo.getValue()},
655 752
	    success:function(form, action) {
656 753
		confpanel.enable();
657 754
	    }
658 755
	});
756
    }
757

  
758
    confcombo.on('select', function() {
759
        if (confcombo.getValue() == '')
760
            delButton.disable();
761
        else
762
            delButton.enable();
763
        loadConfig();
764
    });
765

  
766
    confpanel.on('render', function() {
767
        loadConfig();
659 768
    });
660 769

  
661 770

  
662 771
    function saveChanges() {
772
        var config_name = confcombo.getValue();
663 773
	confpanel.getForm().submit({
664 774
	    url:'dvr', 
665
	    params:{'op':'saveSettings'},
775
	    params:{'op':'saveSettings','config_name':config_name},
666 776
	    waitMsg:'Saving Data...',
777
            success: function(form, action) {
778
                confcombo.setValue(config_name);
779
                confcombo.fireEvent('select');
780
            },
667 781
	    failure: function(form, action) {
668 782
		Ext.Msg.alert('Save failed', action.result.errormsg);
669 783
	    }
670 784
	});
671 785
    }
672 786

  
787
    function deleteConfiguration() {
788
        if (confcombo.getValue() != "") {
789
            Ext.MessageBox.confirm('Message',
790
                         'Do you really want to delete DVR configuration \'' + 
791
                                confcombo.getValue() + '\'?', 
792
                          deleteAction);
... This diff was truncated because it exceeds the maximum size that can be displayed.
(7-7/7)