e, 0, 0,
perm->aa_username,
perm->aa_representative,
- NULL, DVR_PRIO_NORMAL, DVR_RET_DVRCONFIG,
- DVR_RET_DVRCONFIG, comment);
+ NULL, DVR_PRIO_NORMAL, DVR_RET_REM_DVRCONFIG,
+ DVR_RET_REM_DVRCONFIG, comment);
if (de)
idnode_changed(&de->de_id);
}
int dvr_clone;
uint32_t dvr_rerecord_errors;
uint32_t dvr_retention_days;
+ uint32_t dvr_retention_minimal;
uint32_t dvr_removal_days;
uint32_t dvr_autorec_max_count;
uint32_t dvr_autorec_max_sched_count;
} dvr_rs_state_t;
typedef enum {
- DVR_RET_DVRCONFIG = 0,
- DVR_RET_1DAY = 1,
- DVR_RET_3DAY = 3,
- DVR_RET_5DAY = 5,
- DVR_RET_1WEEK = 7,
- DVR_RET_2WEEK = 14,
- DVR_RET_3WEEK = 21,
- DVR_RET_1MONTH = (30+1),
- DVR_RET_2MONTH = (60+2),
- DVR_RET_3MONTH = (90+2),
- DVR_RET_6MONTH = (180+3),
- DVR_RET_1YEAR = (365+1),
- DVR_RET_2YEARS = (2*365+1),
- DVR_RET_3YEARS = (3*365+1),
- DVR_RET_ONREMOVE = INT32_MAX-1, // for retention only
- DVR_RET_SPACE = INT32_MAX-1, // for removal only
- DVR_RET_FOREVER = INT32_MAX
-} dvr_retention_t;
+ DVR_RET_MIN_DISABLED = 0, /* For dvr config minimal retention only */
+ DVR_RET_REM_DVRCONFIG = 0,
+ DVR_RET_REM_1DAY = 1,
+ DVR_RET_REM_3DAY = 3,
+ DVR_RET_REM_5DAY = 5,
+ DVR_RET_REM_1WEEK = 7,
+ DVR_RET_REM_2WEEK = 14,
+ DVR_RET_REM_3WEEK = 21,
+ DVR_RET_REM_1MONTH = (30+1),
+ DVR_RET_REM_2MONTH = (60+2),
+ DVR_RET_REM_3MONTH = (90+2),
+ DVR_RET_REM_6MONTH = (180+3),
+ DVR_RET_REM_1YEAR = (365+1),
+ DVR_RET_REM_2YEARS = (2*365+1),
+ DVR_RET_REM_3YEARS = (3*365+1),
+ DVR_RET_ONREMOVE = INT32_MAX-1, /* For retention only */
+ DVR_REM_SPACE = INT32_MAX-1, /* For removal only */
+ DVR_RET_REM_FOREVER = INT32_MAX
+} dvr_retention_removal_t;
typedef struct dvr_entry {
int de_pri;
int de_dont_reschedule;
int de_dont_rerecord;
+ uint32_t de_file_removed;
uint32_t de_retention;
uint32_t de_removal;
static inline uint32_t dvr_retention_cleanup(uint32_t val)
{
- return val > DVR_RET_FOREVER ? DVR_RET_FOREVER : val;
+ return val > DVR_RET_REM_FOREVER ? DVR_RET_REM_FOREVER : val;
}
/*
int dvr_entry_delete(dvr_entry_t *de);
-void dvr_entry_cancel_delete(dvr_entry_t *de, int rerecord);
+void dvr_entry_cancel_delete(dvr_entry_t *de, int rerecord, int forcedestroy);
+
+void dvr_entry_trydestroy(dvr_entry_t *de);
int dvr_entry_file_moved(const char *src, const char *dst);
if (de_prev) {
tvhinfo(LS_DVR, "autorec %s removing recordings %s (allowed count %u total %u)",
dae->dae_name, idnode_uuid_as_str(&de_prev->de_id, ubuf), max_count, total);
- dvr_entry_cancel_delete(de_prev, 0);
+ dvr_entry_cancel_delete(de_prev, 0, 0);
}
}
}
.id = "retention",
.name = N_("DVR log retention"),
.desc = N_("Number of days to retain infomation about recording."),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.off = offsetof(dvr_autorec_entry_t, dae_retention),
.list = dvr_entry_class_retention_list,
.opts = PO_HIDDEN | PO_EXPERT | PO_DOC_NLIST,
.id = "removal",
.name = N_("DVR file retention period"),
.desc = N_("Number of days to keep the recorded file."),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.off = offsetof(dvr_autorec_entry_t, dae_removal),
.list = dvr_entry_class_removal_list,
.opts = PO_HIDDEN | PO_ADVANCED | PO_DOC_NLIST,
dvr_autorec_get_retention_days( dvr_autorec_entry_t *dae )
{
if (dae->dae_retention > 0) {
- if (dae->dae_retention > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (dae->dae_retention > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
uint32_t removal = dvr_autorec_get_removal_days(dae);
/* As we need the db entry when deleting the file on disk */
- if (removal != DVR_RET_FOREVER && removal > dae->dae_retention)
+ if (removal != DVR_RET_REM_FOREVER && removal > dae->dae_retention)
return DVR_RET_ONREMOVE;
return dae->dae_retention;
dvr_autorec_get_removal_days( dvr_autorec_entry_t *dae )
{
if (dae->dae_removal > 0) {
- if (dae->dae_removal > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (dae->dae_removal > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
return dae->dae_removal;
}
cfg->dvr_enabled = 1;
cfg->dvr_config_name = strdup(name);
cfg->dvr_retention_days = DVR_RET_ONREMOVE;
- cfg->dvr_removal_days = DVR_RET_FOREVER;
+ cfg->dvr_retention_minimal = DVR_RET_MIN_DISABLED;
+ cfg->dvr_removal_days = DVR_RET_REM_FOREVER;
cfg->dvr_clone = 1;
cfg->dvr_tag_files = 1;
cfg->dvr_skip_commercials = 1;
dvr_config_storage_check(cfg);
if (cfg->dvr_cleanup_threshold_free < 50)
cfg->dvr_cleanup_threshold_free = 50; // as checking is only periodically, lower is not save
- if (cfg->dvr_removal_days != DVR_RET_FOREVER &&
+ if (cfg->dvr_removal_days != DVR_RET_REM_FOREVER &&
cfg->dvr_removal_days > cfg->dvr_retention_days)
cfg->dvr_retention_days = DVR_RET_ONREMOVE;
- if (cfg->dvr_removal_days > DVR_RET_FOREVER)
- cfg->dvr_removal_days = DVR_RET_FOREVER;
- if (cfg->dvr_retention_days > DVR_RET_FOREVER)
- cfg->dvr_retention_days = DVR_RET_FOREVER;
+ if (cfg->dvr_removal_days > DVR_RET_REM_FOREVER)
+ cfg->dvr_removal_days = DVR_RET_REM_FOREVER;
+ if (cfg->dvr_retention_days > DVR_RET_REM_FOREVER)
+ cfg->dvr_retention_days = DVR_RET_REM_FOREVER;
}
dvr_config_class_removal_list ( void *o, const char *lang )
{
static const struct strtab_u32 tab[] = {
- { N_("1 day"), DVR_RET_1DAY },
- { N_("3 days"), DVR_RET_3DAY },
- { N_("5 days"), DVR_RET_5DAY },
- { N_("1 week"), DVR_RET_1WEEK },
- { N_("2 weeks"), DVR_RET_2WEEK },
- { N_("3 weeks"), DVR_RET_3WEEK },
- { N_("1 month"), DVR_RET_1MONTH },
- { N_("2 months"), DVR_RET_2MONTH },
- { N_("3 months"), DVR_RET_3MONTH },
- { N_("6 months"), DVR_RET_6MONTH },
- { N_("1 year"), DVR_RET_1YEAR },
- { N_("2 years"), DVR_RET_2YEARS },
- { N_("3 years"), DVR_RET_3YEARS },
- { N_("Maintained space"), DVR_RET_SPACE },
- { N_("Forever"), DVR_RET_FOREVER },
+ { N_("1 day"), DVR_RET_REM_1DAY },
+ { N_("3 days"), DVR_RET_REM_3DAY },
+ { N_("5 days"), DVR_RET_REM_5DAY },
+ { N_("1 week"), DVR_RET_REM_1WEEK },
+ { N_("2 weeks"), DVR_RET_REM_2WEEK },
+ { N_("3 weeks"), DVR_RET_REM_3WEEK },
+ { N_("1 month"), DVR_RET_REM_1MONTH },
+ { N_("2 months"), DVR_RET_REM_2MONTH },
+ { N_("3 months"), DVR_RET_REM_3MONTH },
+ { N_("6 months"), DVR_RET_REM_6MONTH },
+ { N_("1 year"), DVR_RET_REM_1YEAR },
+ { N_("2 years"), DVR_RET_REM_2YEARS },
+ { N_("3 years"), DVR_RET_REM_3YEARS },
+ { N_("Maintained space"), DVR_REM_SPACE },
+ { N_("Forever"), DVR_RET_REM_FOREVER },
};
return strtab2htsmsg_u32(tab, 1, lang);
}
dvr_config_class_retention_list ( void *o, const char *lang )
{
static const struct strtab_u32 tab[] = {
- { N_("1 day"), DVR_RET_1DAY },
- { N_("3 days"), DVR_RET_3DAY },
- { N_("5 days"), DVR_RET_5DAY },
- { N_("1 week"), DVR_RET_1WEEK },
- { N_("2 weeks"), DVR_RET_2WEEK },
- { N_("3 weeks"), DVR_RET_3WEEK },
- { N_("1 month"), DVR_RET_1MONTH },
- { N_("2 months"), DVR_RET_2MONTH },
- { N_("3 months"), DVR_RET_3MONTH },
- { N_("6 months"), DVR_RET_6MONTH },
- { N_("1 year"), DVR_RET_1YEAR },
- { N_("2 years"), DVR_RET_2YEARS },
- { N_("3 years"), DVR_RET_3YEARS },
+ { N_("1 day"), DVR_RET_REM_1DAY },
+ { N_("3 days"), DVR_RET_REM_3DAY },
+ { N_("5 days"), DVR_RET_REM_5DAY },
+ { N_("1 week"), DVR_RET_REM_1WEEK },
+ { N_("2 weeks"), DVR_RET_REM_2WEEK },
+ { N_("3 weeks"), DVR_RET_REM_3WEEK },
+ { N_("1 month"), DVR_RET_REM_1MONTH },
+ { N_("2 months"), DVR_RET_REM_2MONTH },
+ { N_("3 months"), DVR_RET_REM_3MONTH },
+ { N_("6 months"), DVR_RET_REM_6MONTH },
+ { N_("1 year"), DVR_RET_REM_1YEAR },
+ { N_("2 years"), DVR_RET_REM_2YEARS },
+ { N_("3 years"), DVR_RET_REM_3YEARS },
{ N_("On file removal"), DVR_RET_ONREMOVE },
- { N_("Forever"), DVR_RET_FOREVER },
+ { N_("Forever"), DVR_RET_REM_FOREVER },
+ };
+ return strtab2htsmsg_u32(tab, 1, lang);
+}
+
+static htsmsg_t *
+dvr_config_class_retention_list_minimal ( void *o, const char *lang )
+{
+ static const struct strtab_u32 tab[] = {
+ { N_("Disabled"), DVR_RET_MIN_DISABLED },
+ { N_("1 day"), DVR_RET_REM_1DAY },
+ { N_("3 days"), DVR_RET_REM_3DAY },
+ { N_("5 days"), DVR_RET_REM_5DAY },
+ { N_("1 week"), DVR_RET_REM_1WEEK },
+ { N_("2 weeks"), DVR_RET_REM_2WEEK },
+ { N_("3 weeks"), DVR_RET_REM_3WEEK },
+ { N_("1 month"), DVR_RET_REM_1MONTH },
+ { N_("2 months"), DVR_RET_REM_2MONTH },
+ { N_("3 months"), DVR_RET_REM_3MONTH },
+ { N_("6 months"), DVR_RET_REM_6MONTH },
+ { N_("1 year"), DVR_RET_REM_1YEAR },
+ { N_("2 years"), DVR_RET_REM_2YEARS },
+ { N_("3 years"), DVR_RET_REM_3YEARS },
+ { N_("Forever"), DVR_RET_REM_FOREVER },
};
return strtab2htsmsg_u32(tab, 1, lang);
}
.type = PT_U32,
.id = "retention-days",
.name = N_("DVR log retention period"),
- .desc = N_("Number of days to retain infomation about recordings."),
+ .desc = N_("Number of days to retain information about recordings. Once this period is exceeded, duplicate detection will not be possible for this recording."),
.off = offsetof(dvr_config_t, dvr_retention_days),
.def.u32 = DVR_RET_ONREMOVE,
.list = dvr_config_class_retention_list,
.opts = PO_EXPERT | PO_DOC_NLIST,
.group = 1,
},
+ {
+ .type = PT_U32,
+ .id = "retention-minimal",
+ .name = N_("Minimal log retention period"),
+ .desc = N_("Minimal number of days to retain information from recordings that where deleted manually. Once this period is exceeded, duplicate detection will not be possible for this recording."),
+ .off = offsetof(dvr_config_t, dvr_retention_minimal),
+ .def.u32 = DVR_RET_MIN_DISABLED,
+ .list = dvr_config_class_retention_list_minimal,
+ .opts = PO_EXPERT | PO_DOC_NLIST,
+ .group = 1,
+ },
{
.type = PT_U32,
.id = "removal-days",
.name = N_("DVR file retention period"),
.desc = N_("Number of days to keep the recorded files."),
.off = offsetof(dvr_config_t, dvr_removal_days),
- .def.u32 = DVR_RET_FOREVER,
+ .def.u32 = DVR_RET_REM_FOREVER,
.list = dvr_config_class_removal_list,
.opts = PO_DOC_NLIST,
.group = 1,
char buf[24];
uint32_t removal = dvr_entry_get_removal_days(de);
- if (removal < DVR_RET_SPACE)
+ if (removal < DVR_REM_SPACE)
snprintf(buf, sizeof(buf), "%i days", removal);
- else if (removal == DVR_RET_SPACE)
+ else if (removal == DVR_REM_SPACE)
return strdup("Until space needed");
else
return strdup("Forever");
dvr_entry_get_retention_days( dvr_entry_t *de )
{
if (de->de_retention > 0) {
- if (de->de_retention > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (de->de_retention > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
/* As we need the db entry when deleting the file on disk */
- if (dvr_entry_get_removal_days(de) != DVR_RET_FOREVER &&
- dvr_entry_get_removal_days(de) > de->de_retention)
+ if (dvr_entry_get_removal_days(de) != DVR_RET_REM_FOREVER &&
+ dvr_entry_get_removal_days(de) > de->de_retention && !de->de_file_removed)
return DVR_RET_ONREMOVE;
return de->de_retention;
dvr_entry_get_removal_days ( dvr_entry_t *de )
{
if (de->de_removal > 0) {
- if (de->de_removal > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (de->de_removal > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
return de->de_removal;
}
uint32_t retention = dvr_entry_get_retention_days(de);
int save;
- if ((removal > 0 || retention == 0) && removal < DVR_RET_SPACE) {
+ if ((removal > 0 || retention == 0) && removal < DVR_REM_SPACE && !de->de_file_removed) {
stop = time_t_out_of_range((int64_t)de->de_stop + removal * (int64_t)86400);
if (stop > gclk()) {
dvr_entry_retention_arm(de, dvr_timer_remove_files, stop);
}
if(de->de_data_errors >= DVR_MAX_DATA_ERRORS) /* user configurable threshold? */
return N_("Too many data errors");
- if(dvr_get_filesize(de, 0) == -1)
+ if (de->de_file_removed)
+ return N_("File removed");
+ if (dvr_get_filesize(de, 0) == -1)
return N_("File missing");
if(de->de_last_error)
return streaming_code2txt(de->de_last_error);
break;
case DVR_COMPLETED:
s = "completed";
- if(de->de_last_error || dvr_get_filesize(de, 0) == -1)
+ if(de->de_last_error ||
+ (dvr_get_filesize(de, 0) == -1 && !de->de_file_removed))
s = "completedError";
rerecord = de->de_dont_rerecord ? 0 : dvr_entry_get_rerecord_errors(de);
if(rerecord && (de->de_errors || de->de_data_errors > rerecord))
if (fsize1 / 5 < fsize2 / 6) {
goto not_so_good;
} else {
- dvr_entry_cancel_delete(de2, 1);
+ dvr_entry_cancel_delete(de2, 1, 1);
}
} else if (de->de_sched_state == DVR_COMPLETED) {
if(dvr_get_filesize(de, 0) == -1) {
delete_me:
- dvr_entry_cancel_delete(de, 0);
+ dvr_entry_cancel_delete(de, 0, 1);
dvr_entry_rerecord(de2);
return 1;
}
not_so_good:
de->de_retention = DVR_RET_ONREMOVE;
- de->de_removal = DVR_RET_1DAY;
+ de->de_removal = DVR_RET_REM_1DAY;
dvr_entry_change_parent_child(de->de_parent, NULL, NULL, 1);
dvr_entry_completed(de, SM_CODE_WEAK_STREAM);
return 0;
// if duplicate, then delete it now, don't record!
if (_dvr_duplicate_event(de)) {
- dvr_entry_cancel_delete(de, 1);
+ dvr_entry_cancel_delete(de, 1, 1);
return;
}
static void
dvr_entry_class_delete(idnode_t *self)
{
- dvr_entry_cancel_delete((dvr_entry_t *)self, 0);
+ dvr_entry_t *de = (dvr_entry_t *)self;
+ dvr_entry_cancel_delete(de, 0, 0);
}
static int
dvr_entry_class_retention_list ( void *o, const char *lang )
{
static const struct strtab_u32 tab[] = {
- { N_("DVR configuration"), DVR_RET_DVRCONFIG },
- { N_("1 day"), DVR_RET_1DAY },
- { N_("3 days"), DVR_RET_3DAY },
- { N_("5 days"), DVR_RET_5DAY },
- { N_("1 week"), DVR_RET_1WEEK },
- { N_("2 weeks"), DVR_RET_2WEEK },
- { N_("3 weeks"), DVR_RET_3WEEK },
- { N_("1 month"), DVR_RET_1MONTH },
- { N_("2 months"), DVR_RET_2MONTH },
- { N_("3 months"), DVR_RET_3MONTH },
- { N_("6 months"), DVR_RET_6MONTH },
- { N_("1 year"), DVR_RET_1YEAR },
- { N_("2 years"), DVR_RET_2YEARS },
- { N_("3 years"), DVR_RET_3YEARS },
+ { N_("DVR configuration"), DVR_RET_REM_DVRCONFIG },
+ { N_("1 day"), DVR_RET_REM_1DAY },
+ { N_("3 days"), DVR_RET_REM_3DAY },
+ { N_("5 days"), DVR_RET_REM_5DAY },
+ { N_("1 week"), DVR_RET_REM_1WEEK },
+ { N_("2 weeks"), DVR_RET_REM_2WEEK },
+ { N_("3 weeks"), DVR_RET_REM_3WEEK },
+ { N_("1 month"), DVR_RET_REM_1MONTH },
+ { N_("2 months"), DVR_RET_REM_2MONTH },
+ { N_("3 months"), DVR_RET_REM_3MONTH },
+ { N_("6 months"), DVR_RET_REM_6MONTH },
+ { N_("1 year"), DVR_RET_REM_1YEAR },
+ { N_("2 years"), DVR_RET_REM_2YEARS },
+ { N_("3 years"), DVR_RET_REM_3YEARS },
{ N_("On file removal"), DVR_RET_ONREMOVE },
- { N_("Forever"), DVR_RET_FOREVER },
+ { N_("Forever"), DVR_RET_REM_FOREVER },
};
return strtab2htsmsg_u32(tab, 1, lang);
}
dvr_entry_class_removal_list ( void *o, const char *lang )
{
static const struct strtab_u32 tab[] = {
- { N_("DVR configuration"), DVR_RET_DVRCONFIG },
- { N_("1 day"), DVR_RET_1DAY },
- { N_("3 days"), DVR_RET_3DAY },
- { N_("5 days"), DVR_RET_5DAY },
- { N_("1 week"), DVR_RET_1WEEK },
- { N_("2 weeks"), DVR_RET_2WEEK },
- { N_("3 weeks"), DVR_RET_3WEEK },
- { N_("1 month"), DVR_RET_1MONTH },
- { N_("2 months"), DVR_RET_2MONTH },
- { N_("3 months"), DVR_RET_3MONTH },
- { N_("6 months"), DVR_RET_6MONTH },
- { N_("1 year"), DVR_RET_1YEAR },
- { N_("2 years"), DVR_RET_2YEARS },
- { N_("3 years"), DVR_RET_3YEARS },
- { N_("Maintained space"), DVR_RET_SPACE },
- { N_("Forever"), DVR_RET_FOREVER },
+ { N_("DVR configuration"), DVR_RET_REM_DVRCONFIG },
+ { N_("1 day"), DVR_RET_REM_1DAY },
+ { N_("3 days"), DVR_RET_REM_3DAY },
+ { N_("5 days"), DVR_RET_REM_5DAY },
+ { N_("1 week"), DVR_RET_REM_1WEEK },
+ { N_("2 weeks"), DVR_RET_REM_2WEEK },
+ { N_("3 weeks"), DVR_RET_REM_3WEEK },
+ { N_("1 month"), DVR_RET_REM_1MONTH },
+ { N_("2 months"), DVR_RET_REM_2MONTH },
+ { N_("3 months"), DVR_RET_REM_3MONTH },
+ { N_("6 months"), DVR_RET_REM_6MONTH },
+ { N_("1 year"), DVR_RET_REM_1YEAR },
+ { N_("2 years"), DVR_RET_REM_2YEARS },
+ { N_("3 years"), DVR_RET_REM_3YEARS },
+ { N_("Maintained space"), DVR_REM_SPACE },
+ { N_("Forever"), DVR_RET_REM_FOREVER },
};
return strtab2htsmsg_u32(tab, 1, lang);
}
.name = N_("DVR log retention"),
.desc = N_("Number of days to retain entry information."),
.off = offsetof(dvr_entry_t, de_retention),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.list = dvr_entry_class_retention_list,
.opts = PO_HIDDEN | PO_EXPERT | PO_DOC_NLIST,
},
.name = N_("DVR file retention period"),
.desc = N_("Number of days to keep the file."),
.off = offsetof(dvr_entry_t, de_removal),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.list = dvr_entry_class_removal_list,
.opts = PO_HIDDEN | PO_ADVANCED | PO_DOC_NLIST,
},
.off = offsetof(dvr_entry_t, de_dont_rerecord),
.opts = PO_HIDDEN | PO_ADVANCED,
},
+ {
+ .type = PT_U32,
+ .id = "fileremoved",
+ .name = N_("File removed"),
+ .desc = N_("The recorded file was removed intentionally"),
+ .off = offsetof(dvr_entry_t, de_file_removed),
+ .opts = PO_HIDDEN | PO_NOUI,
+ },
{
.type = PT_STR,
.id = "autorec",
htsmsg_delete_field(m, "filename");
ret = 1;
}
+ de->de_file_removed = 1;
}
return ret;
if (cmd == 0 && !de->de_dont_rerecord) {
de->de_dont_rerecord = 1;
if (de->de_child)
- dvr_entry_cancel_delete(de->de_child, 0);
+ dvr_entry_cancel_delete(de->de_child, 0, 1);
} else {
de->de_dont_rerecord = 0;
dvr_entry_rerecord(de);
*
*/
void
-dvr_entry_cancel_delete(dvr_entry_t *de, int rerecord)
+dvr_entry_cancel_delete(dvr_entry_t *de, int rerecord, int forcedestroy)
{
dvr_entry_t *parent = de->de_parent;
dvr_autorec_entry_t *dae = de->de_autorec;
dvr_stop_recording(de, SM_CODE_ABORTED, 1, 0);
case DVR_COMPLETED:
dvr_entry_delete(de);
- dvr_entry_destroy(de, 1);
+ if (forcedestroy)
+ dvr_entry_destroy(de, 1);
+ else
+ dvr_entry_trydestroy(de);
break;
case DVR_SCHEDULED:
// Trigger autorec update in case of max sched count limit
if (dae && dae->dae_max_sched_count > 0)
dvr_autorec_changed(dae, 0);
+}
+
+/**
+ * Destroy db entry if possible.
+ * The deletion of the db entry can be prevented by the minimal retention setting.
+ * Prevention is needed in order to keep duplicate detection happy.
+ */
+void
+dvr_entry_trydestroy(dvr_entry_t *de)
+{
+ char ubuf[UUID_HEX_SIZE];
+ uint32_t minretention, removal;
+ if (!de->de_config || de->de_config->dvr_retention_minimal == DVR_RET_MIN_DISABLED)
+ dvr_entry_destroy(de, 1);
+ else {
+ minretention = time_t_out_of_range((int64_t)de->de_stop + de->de_config->dvr_retention_minimal * (int64_t)86400);
+ if (minretention < gclk()) /* Minimal retention period expired -> deleting db entry allowed */
+ dvr_entry_destroy(de, 1);
+ else {
+ removal = (gclk() - (int64_t)de->de_stop)/(int64_t)86400;
+
+ de->de_removal = removal > DVR_RET_REM_DVRCONFIG ?
+ removal : DVR_RET_REM_1DAY; /* Update removal to the current value */
+ de->de_retention = de->de_config->dvr_retention_minimal; /* Update the retention to the minimum allowed value */
+ idnode_changed(&de->de_id);
+ dvr_entry_retention_timer(de); /* Rearm timer as retention was changed */
+
+ tvhinfo(LS_DVR, "delete entry %s not allowed \"%s\" on \"%s\", current retention period %"PRIu32", "
+ "minimal retention period %"PRIu32"",
+ idnode_uuid_as_str(&de->de_id, ubuf),
+ lang_str_get(de->de_title, NULL), DVR_CH_NAME(de),
+ removal, de->de_config->dvr_retention_minimal);
+ }
+ }
}
/**
.id = "retention",
.name = N_("DVR log retention"),
.desc = N_("Number of days to retain entry information."),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.off = offsetof(dvr_timerec_entry_t, dte_retention),
.list = dvr_entry_class_retention_list,
.opts = PO_EXPERT | PO_DOC_NLIST,
.id = "removal",
.name = N_("DVR file retention period"),
.desc = N_("Number of days to keep the recorded file."),
- .def.i = DVR_RET_DVRCONFIG,
+ .def.i = DVR_RET_REM_DVRCONFIG,
.off = offsetof(dvr_timerec_entry_t, dte_removal),
.list = dvr_entry_class_removal_list,
.opts = PO_ADVANCED | PO_DOC_NLIST,
dvr_timerec_get_retention_days( dvr_timerec_entry_t *dte )
{
if (dte->dte_retention > 0) {
- if (dte->dte_retention > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (dte->dte_retention > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
/* As we need the db entry when deleting the file on disk */
- if (dvr_timerec_get_removal_days(dte) != DVR_RET_FOREVER &&
+ if (dvr_timerec_get_removal_days(dte) != DVR_RET_REM_FOREVER &&
dvr_timerec_get_removal_days(dte) > dte->dte_retention)
return DVR_RET_ONREMOVE;
dvr_timerec_get_removal_days( dvr_timerec_entry_t *dte )
{
if (dte->dte_removal > 0) {
- if (dte->dte_removal > DVR_RET_FOREVER)
- return DVR_RET_FOREVER;
+ if (dte->dte_removal > DVR_RET_REM_FOREVER)
+ return DVR_RET_REM_FOREVER;
return dte->dte_removal;
}
if (dvr_entry_get_stop_time(de) > stoptime)
continue;
- if (dvr_entry_get_removal_days(de) != DVR_RET_SPACE) // only remove the allowed ones
+ if (dvr_entry_get_removal_days(de) != DVR_REM_SPACE) // only remove the allowed ones
continue;
if (dvr_get_filename(de) == NULL || dvr_get_filesize(de, DVR_FILESIZE_TOTAL) <= 0)
if (!(retval = htsmsg_get_u32(in, "enabled", &u32)) || add)
htsmsg_add_u32(conf, "enabled", !retval ? (u32 > 0 ? 1 : 0) : 1); // default on
if (!(retval = htsmsg_get_u32(in, "retention", &u32)) || add)
- htsmsg_add_u32(conf, "retention", !retval ? u32 : DVR_RET_DVRCONFIG);
+ htsmsg_add_u32(conf, "retention", !retval ? u32 : DVR_RET_REM_DVRCONFIG);
if (!(retval = htsmsg_get_u32(in, "removal", &u32)) || add)
- htsmsg_add_u32(conf, "removal", !retval ? u32 : DVR_RET_DVRCONFIG);
+ htsmsg_add_u32(conf, "removal", !retval ? u32 : DVR_RET_REM_DVRCONFIG);
if(!(retval = htsmsg_get_u32(in, "priority", &u32)) || add)
htsmsg_add_u32(conf, "pri", !retval ? u32 : DVR_PRIO_NORMAL);
if ((str = htsmsg_get_str(in, "name")) || add)
if(htsmsg_get_u32(in, "priority", &priority))
priority = DVR_PRIO_NORMAL;
if(htsmsg_get_u32(in, "retention", &retention))
- retention = DVR_RET_DVRCONFIG;
+ retention = DVR_RET_REM_DVRCONFIG;
if(htsmsg_get_u32(in, "removal", &removal))
- removal = DVR_RET_DVRCONFIG;
+ removal = DVR_RET_REM_DVRCONFIG;
comment = htsmsg_get_str(in, "comment");
if (!(lang = htsmsg_get_str(in, "language")))
lang = htsp->htsp_language;
stop = htsmsg_get_s64_or_default(in, "stop", 0);
start_extra = htsmsg_get_s64_or_default(in, "startExtra", 0);
stop_extra = htsmsg_get_s64_or_default(in, "stopExtra", 0);
- retention = htsmsg_get_u32_or_default(in, "retention", DVR_RET_DVRCONFIG);
- removal = htsmsg_get_u32_or_default(in, "removal", DVR_RET_DVRCONFIG);
+ retention = htsmsg_get_u32_or_default(in, "retention", DVR_RET_REM_DVRCONFIG);
+ removal = htsmsg_get_u32_or_default(in, "removal", DVR_RET_REM_DVRCONFIG);
priority = htsmsg_get_u32_or_default(in, "priority", DVR_PRIO_NORMAL);
title = htsmsg_get_str(in, "title");
subtitle = htsmsg_get_str(in, "subtitle");
if (de == NULL)
return out;
- dvr_entry_cancel_delete(de, 0);
+ dvr_entry_cancel_delete(de, 0, 0);
return htsp_success();
}
if((http_arg_get(&hc->hc_req_args, "rec")) != NULL) {
de = dvr_entry_create_by_event(1, NULL, e, 0, 0, hc->hc_username ?: NULL,
hc->hc_representative ?: NULL, NULL,
- DVR_PRIO_NORMAL, DVR_RET_DVRCONFIG,
- DVR_RET_DVRCONFIG, "simpleui");
+ DVR_PRIO_NORMAL, DVR_RET_REM_DVRCONFIG,
+ DVR_RET_REM_DVRCONFIG, "simpleui");
} else if(de != NULL && (http_arg_get(&hc->hc_req_args, "cancel")) != NULL) {
de = dvr_entry_cancel(de, 0);
}