2008-09-17 21:08:17 +00:00
|
|
|
/*
|
|
|
|
* Digital Video Recorder
|
|
|
|
* Copyright (C) 2008 Andreas Öman
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <pthread.h>
|
2008-09-20 12:59:23 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2008-09-17 21:08:17 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2009-03-25 20:49:50 +00:00
|
|
|
#include "settings.h"
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
#include "tvhead.h"
|
|
|
|
#include "dvr.h"
|
|
|
|
#include "notify.h"
|
2009-09-09 21:37:40 +00:00
|
|
|
#include "htsp.h"
|
2010-03-21 10:08:16 +00:00
|
|
|
#include "streaming.h"
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
char *dvr_storage;
|
|
|
|
char *dvr_format;
|
|
|
|
char *dvr_file_postfix;
|
2008-09-20 12:59:23 +00:00
|
|
|
uint32_t dvr_retention_days;
|
2008-09-21 09:37:35 +00:00
|
|
|
int dvr_flags;
|
2009-08-19 19:44:33 +00:00
|
|
|
int dvr_extra_time_pre;
|
|
|
|
int dvr_extra_time_post;
|
2008-10-19 15:08:17 +00:00
|
|
|
char *dvr_postproc;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
static int de_tally;
|
|
|
|
|
|
|
|
|
|
|
|
struct dvr_entry_list dvrentries;
|
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
static void dvr_entry_save(dvr_entry_t *de);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
static void dvr_timer_expire(void *aux);
|
|
|
|
static void dvr_timer_start_recording(void *aux);
|
|
|
|
|
2010-03-21 10:08:16 +00:00
|
|
|
/**
|
|
|
|
* Return printable status for a dvr entry
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
dvr_entry_status(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
switch(de->de_sched_state) {
|
|
|
|
case DVR_SCHEDULED:
|
|
|
|
return "Scheduled for recording";
|
|
|
|
|
|
|
|
case DVR_RECORDING:
|
|
|
|
|
|
|
|
switch(de->de_rec_state) {
|
|
|
|
case DVR_RS_PENDING:
|
2010-06-21 20:52:36 +00:00
|
|
|
return "Waiting for stream";
|
|
|
|
case DVR_RS_WAIT_PROGRAM_START:
|
|
|
|
return "Waiting for program start";
|
2010-03-21 10:08:16 +00:00
|
|
|
case DVR_RS_RUNNING:
|
|
|
|
return "Running";
|
|
|
|
case DVR_RS_COMMERCIAL:
|
|
|
|
return "Commercial break";
|
|
|
|
case DVR_RS_ERROR:
|
|
|
|
return streaming_code2txt(de->de_last_error);
|
|
|
|
default:
|
|
|
|
return "Invalid";
|
|
|
|
}
|
|
|
|
|
|
|
|
case DVR_COMPLETED:
|
|
|
|
if(de->de_last_error)
|
|
|
|
return streaming_code2txt(de->de_last_error);
|
|
|
|
else
|
|
|
|
return "Completed OK";
|
2010-04-26 19:21:02 +00:00
|
|
|
|
|
|
|
case DVR_MISSED_TIME:
|
|
|
|
return "Time missed";
|
|
|
|
|
2010-03-21 10:08:16 +00:00
|
|
|
default:
|
|
|
|
return "Invalid";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
dvr_entry_schedstatus(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
switch(de->de_sched_state) {
|
|
|
|
case DVR_SCHEDULED:
|
|
|
|
return "scheduled";
|
|
|
|
case DVR_RECORDING:
|
|
|
|
if(de->de_last_error)
|
|
|
|
return "recordingError";
|
|
|
|
else
|
|
|
|
return "recording";
|
|
|
|
case DVR_COMPLETED:
|
|
|
|
if(de->de_last_error)
|
|
|
|
return "completedError";
|
|
|
|
else
|
|
|
|
return "completed";
|
2010-04-26 19:21:02 +00:00
|
|
|
case DVR_MISSED_TIME:
|
|
|
|
return "completedError";
|
2010-03-21 10:08:16 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvrdb_changed(void)
|
|
|
|
{
|
2009-03-01 16:51:30 +00:00
|
|
|
htsmsg_t *m = htsmsg_create_map();
|
2008-09-17 21:08:17 +00:00
|
|
|
htsmsg_add_u32(m, "reload", 1);
|
|
|
|
notify_by_msg("dvrdb", m);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-21 10:08:16 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_entry_notify(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
htsmsg_t *m = htsmsg_create_map();
|
|
|
|
|
|
|
|
htsmsg_add_u32(m, "updateEntry", 1);
|
|
|
|
htsmsg_add_u32(m, "id", de->de_id);
|
|
|
|
htsmsg_add_str(m, "status", dvr_entry_status(de));
|
|
|
|
htsmsg_add_str(m, "schedstate", dvr_entry_schedstatus(de));
|
|
|
|
notify_by_msg("dvrdb", m);
|
|
|
|
}
|
|
|
|
|
2008-09-21 09:37:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
2010-03-16 22:59:10 +00:00
|
|
|
dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
|
2008-09-21 09:37:35 +00:00
|
|
|
{
|
|
|
|
struct tm tm;
|
|
|
|
char buf[40];
|
|
|
|
|
|
|
|
if(dvr_flags & DVR_CHANNEL_IN_TITLE)
|
2010-03-16 22:59:10 +00:00
|
|
|
snprintf(output, outlen, "%s-", de->de_channel->ch_name);
|
2008-09-21 09:37:35 +00:00
|
|
|
else
|
|
|
|
output[0] = 0;
|
|
|
|
|
|
|
|
snprintf(output + strlen(output), outlen - strlen(output),
|
2010-03-16 22:59:10 +00:00
|
|
|
"%s", de->de_title);
|
2008-09-21 09:37:35 +00:00
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
localtime_r(&de->de_start, &tm);
|
2008-09-21 09:37:35 +00:00
|
|
|
|
|
|
|
if(dvr_flags & DVR_DATE_IN_TITLE) {
|
|
|
|
strftime(buf, sizeof(buf), "%F", &tm);
|
2010-03-16 23:05:22 +00:00
|
|
|
snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
|
2008-09-21 09:37:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(dvr_flags & DVR_TIME_IN_TITLE) {
|
2009-11-15 21:21:21 +00:00
|
|
|
strftime(buf, sizeof(buf), "%H-%M", &tm);
|
2010-03-16 23:05:22 +00:00
|
|
|
snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
|
2008-09-21 09:37:35 +00:00
|
|
|
}
|
2010-03-16 22:59:10 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2008-09-21 09:37:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_entry_link(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
time_t now, preamble;
|
2008-09-21 09:37:35 +00:00
|
|
|
char buf[100];
|
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
dvr_make_title(buf, sizeof(buf), de);
|
2008-09-21 09:37:35 +00:00
|
|
|
|
|
|
|
de->de_ititle = strdup(buf);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
de->de_refcnt = 1;
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
LIST_INSERT_HEAD(&dvrentries, de, de_global_link);
|
|
|
|
|
|
|
|
time(&now);
|
|
|
|
|
2009-08-19 19:44:33 +00:00
|
|
|
preamble = de->de_start - (60 * de->de_start_extra) - 30;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
if(now >= de->de_stop || de->de_dont_reschedule) {
|
2010-04-26 19:21:02 +00:00
|
|
|
if(de->de_filename == NULL)
|
|
|
|
de->de_sched_state = DVR_MISSED_TIME;
|
|
|
|
else
|
|
|
|
de->de_sched_state = DVR_COMPLETED;
|
2008-09-17 21:08:17 +00:00
|
|
|
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
|
2008-09-20 12:59:23 +00:00
|
|
|
de->de_stop + dvr_retention_days * 86400);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
de->de_sched_state = DVR_SCHEDULED;
|
|
|
|
|
|
|
|
gtimer_arm_abs(&de->de_timer, dvr_timer_start_recording, de, preamble);
|
|
|
|
}
|
2009-09-09 21:37:40 +00:00
|
|
|
htsp_dvr_entry_add(de);
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2009-06-21 20:22:10 +00:00
|
|
|
dvr_entry_t *
|
2009-12-15 20:09:38 +00:00
|
|
|
dvr_entry_create(channel_t *ch, time_t start, time_t stop,
|
|
|
|
const char *title, const char *description,
|
2010-03-16 22:59:10 +00:00
|
|
|
const char *creator, dvr_autorec_entry_t *dae,
|
2010-03-17 21:16:57 +00:00
|
|
|
epg_episode_t *ee, dvr_prio_t pri)
|
2008-09-17 21:08:17 +00:00
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
char tbuf[30];
|
|
|
|
struct tm tm;
|
2009-08-19 19:44:33 +00:00
|
|
|
time_t t;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2009-12-15 20:09:38 +00:00
|
|
|
LIST_FOREACH(de, &ch->ch_dvrs, de_channel_link)
|
|
|
|
if(de->de_start == start && de->de_sched_state != DVR_COMPLETED)
|
2009-06-21 20:22:10 +00:00
|
|
|
return NULL;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
de = calloc(1, sizeof(dvr_entry_t));
|
|
|
|
de->de_id = ++de_tally;
|
|
|
|
|
2009-12-15 20:09:38 +00:00
|
|
|
ch = de->de_channel = ch;
|
2008-09-17 21:08:17 +00:00
|
|
|
LIST_INSERT_HEAD(&de->de_channel->ch_dvrs, de, de_channel_link);
|
|
|
|
|
2009-12-15 20:09:38 +00:00
|
|
|
de->de_start = start;
|
|
|
|
de->de_stop = stop;
|
2010-03-17 21:16:57 +00:00
|
|
|
de->de_pri = pri;
|
2009-10-29 19:17:13 +00:00
|
|
|
if (ch->ch_dvr_extra_time_pre)
|
|
|
|
de->de_start_extra = ch->ch_dvr_extra_time_pre;
|
|
|
|
else
|
|
|
|
de->de_start_extra = dvr_extra_time_pre;
|
|
|
|
if (ch->ch_dvr_extra_time_post)
|
|
|
|
de->de_stop_extra = ch->ch_dvr_extra_time_post;
|
|
|
|
else
|
|
|
|
de->de_stop_extra = dvr_extra_time_post;
|
2008-09-17 21:08:17 +00:00
|
|
|
de->de_creator = strdup(creator);
|
2009-12-15 20:09:38 +00:00
|
|
|
de->de_title = strdup(title);
|
|
|
|
de->de_desc = description ? strdup(description) : NULL;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
dvr_entry_link(de);
|
|
|
|
|
2009-11-26 20:37:36 +00:00
|
|
|
t = de->de_start - de->de_start_extra * 60;
|
2009-08-19 19:44:33 +00:00
|
|
|
localtime_r(&t, &tm);
|
2008-09-17 21:08:17 +00:00
|
|
|
strftime(tbuf, sizeof(tbuf), "%c", &tm);
|
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
if(dae != NULL) {
|
|
|
|
de->de_autorec = dae;
|
|
|
|
LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link);
|
|
|
|
}
|
2010-03-16 19:54:45 +00:00
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\" starting at %s, "
|
|
|
|
"scheduled for recording by \"%s\"",
|
|
|
|
de->de_title, de->de_channel->ch_name, tbuf, creator);
|
|
|
|
|
|
|
|
dvrdb_changed();
|
2008-09-20 12:59:23 +00:00
|
|
|
dvr_entry_save(de);
|
2009-06-21 20:22:10 +00:00
|
|
|
return de;
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-15 20:09:38 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
dvr_entry_t *
|
2010-03-16 19:54:45 +00:00
|
|
|
dvr_entry_create_by_event(event_t *e, const char *creator,
|
2010-03-17 22:17:16 +00:00
|
|
|
dvr_autorec_entry_t *dae, dvr_prio_t pri)
|
2009-12-15 20:09:38 +00:00
|
|
|
{
|
|
|
|
if(e->e_channel == NULL || e->e_title == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return dvr_entry_create(e->e_channel, e->e_start, e->e_stop,
|
2010-03-17 21:16:57 +00:00
|
|
|
e->e_title, e->e_desc, creator, dae, &e->e_episode,
|
2010-03-17 22:17:16 +00:00
|
|
|
pri);
|
2010-03-16 19:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae)
|
|
|
|
{
|
|
|
|
char buf[200];
|
|
|
|
|
2010-03-27 05:45:31 +00:00
|
|
|
if(dae->dae_creator) {
|
|
|
|
snprintf(buf, sizeof(buf), "Auto recording by: %s", dae->dae_creator);
|
|
|
|
} else {
|
|
|
|
snprintf(buf, sizeof(buf), "Auto recording");
|
|
|
|
}
|
2010-03-17 22:17:16 +00:00
|
|
|
dvr_entry_create_by_event(e, buf, dae, dae->dae_pri);
|
2009-12-15 20:09:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2008-09-20 06:06:41 +00:00
|
|
|
void
|
|
|
|
dvr_entry_dec_ref(dvr_entry_t *de)
|
2008-09-17 21:08:17 +00:00
|
|
|
{
|
2008-09-20 06:06:41 +00:00
|
|
|
lock_assert(&global_lock);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
if(de->de_refcnt > 1) {
|
|
|
|
de->de_refcnt--;
|
|
|
|
return;
|
|
|
|
}
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2010-03-16 19:54:45 +00:00
|
|
|
if(de->de_autorec != NULL)
|
|
|
|
LIST_REMOVE(de, de_autorec_link);
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
free(de->de_creator);
|
|
|
|
free(de->de_title);
|
2008-09-21 09:37:35 +00:00
|
|
|
free(de->de_ititle);
|
2008-09-17 21:08:17 +00:00
|
|
|
free(de->de_desc);
|
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
free(de->de_episode.ee_onscreen);
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
free(de);
|
2008-09-20 06:06:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_entry_remove(dvr_entry_t *de)
|
|
|
|
{
|
2008-09-21 18:17:28 +00:00
|
|
|
hts_settings_remove("dvr/log/%d", de->de_id);
|
2008-09-20 06:06:41 +00:00
|
|
|
|
2009-09-09 21:37:40 +00:00
|
|
|
htsp_dvr_entry_delete(de);
|
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
gtimer_disarm(&de->de_timer);
|
|
|
|
|
|
|
|
LIST_REMOVE(de, de_channel_link);
|
|
|
|
LIST_REMOVE(de, de_global_link);
|
2010-06-21 20:52:36 +00:00
|
|
|
de->de_channel = NULL;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
dvrdb_changed();
|
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
dvr_entry_dec_ref(de);
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_db_load_one(htsmsg_t *c, int id)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
const char *s, *title, *creator;
|
|
|
|
channel_t *ch;
|
|
|
|
uint32_t start, stop;
|
2009-08-19 19:44:33 +00:00
|
|
|
int d;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
if(htsmsg_get_u32(c, "start", &start))
|
|
|
|
return;
|
|
|
|
if(htsmsg_get_u32(c, "stop", &stop))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if((s = htsmsg_get_str(c, "channel")) == NULL)
|
|
|
|
return;
|
2010-06-04 20:59:18 +00:00
|
|
|
if((ch = channel_find_by_name(s, 0, 0)) == NULL)
|
2008-09-17 21:08:17 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if((title = htsmsg_get_str(c, "title")) == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if((creator = htsmsg_get_str(c, "creator")) == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
de = calloc(1, sizeof(dvr_entry_t));
|
|
|
|
de->de_id = id;
|
|
|
|
|
|
|
|
de_tally = MAX(id, de_tally);
|
|
|
|
|
|
|
|
de->de_channel = ch;
|
|
|
|
LIST_INSERT_HEAD(&de->de_channel->ch_dvrs, de, de_channel_link);
|
|
|
|
|
|
|
|
de->de_start = start;
|
|
|
|
de->de_stop = stop;
|
|
|
|
de->de_creator = strdup(creator);
|
|
|
|
de->de_title = strdup(title);
|
2010-03-17 21:16:57 +00:00
|
|
|
de->de_pri = dvr_pri2val(htsmsg_get_str(c, "pri"));
|
2009-08-19 19:44:33 +00:00
|
|
|
|
|
|
|
if(htsmsg_get_s32(c, "start_extra", &d))
|
|
|
|
de->de_start_extra = dvr_extra_time_pre;
|
|
|
|
else
|
|
|
|
de->de_start_extra = d;
|
|
|
|
|
|
|
|
if(htsmsg_get_s32(c, "stop_extra", &d))
|
|
|
|
de->de_stop_extra = dvr_extra_time_post;
|
|
|
|
else
|
|
|
|
de->de_stop_extra = d;
|
|
|
|
|
2010-03-17 21:16:57 +00:00
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
tvh_str_set(&de->de_desc, htsmsg_get_str(c, "description"));
|
|
|
|
tvh_str_set(&de->de_filename, htsmsg_get_str(c, "filename"));
|
2010-03-21 10:08:16 +00:00
|
|
|
|
|
|
|
htsmsg_get_u32(c, "errorcode", &de->de_last_error);
|
|
|
|
htsmsg_get_u32(c, "errors", &de->de_errors);
|
2008-09-20 06:06:41 +00:00
|
|
|
|
|
|
|
htsmsg_get_u32(c, "noresched", &de->de_dont_reschedule);
|
2010-03-16 19:54:45 +00:00
|
|
|
|
|
|
|
s = htsmsg_get_str(c, "autorec");
|
|
|
|
if(s != NULL) {
|
|
|
|
dvr_autorec_entry_t *dae = autorec_entry_find(s, 0);
|
|
|
|
|
|
|
|
if(dae != NULL) {
|
|
|
|
de->de_autorec = dae;
|
|
|
|
LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
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"));
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
dvr_entry_link(de);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_db_load(void)
|
|
|
|
{
|
|
|
|
htsmsg_t *l, *c;
|
|
|
|
htsmsg_field_t *f;
|
|
|
|
|
2008-09-21 18:17:28 +00:00
|
|
|
if((l = hts_settings_load("dvr/log")) != NULL) {
|
2008-09-17 21:08:17 +00:00
|
|
|
HTSMSG_FOREACH(f, l) {
|
2009-03-01 16:51:30 +00:00
|
|
|
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
2008-09-17 21:08:17 +00:00
|
|
|
continue;
|
|
|
|
dvr_db_load_one(c, atoi(f->hmf_name));
|
|
|
|
}
|
2008-09-28 12:17:17 +00:00
|
|
|
htsmsg_destroy(l);
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
2008-09-20 12:59:23 +00:00
|
|
|
dvr_entry_save(dvr_entry_t *de)
|
2008-09-17 21:08:17 +00:00
|
|
|
{
|
2009-03-01 16:51:30 +00:00
|
|
|
htsmsg_t *m = htsmsg_create_map();
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
lock_assert(&global_lock);
|
|
|
|
|
|
|
|
htsmsg_add_str(m, "channel", de->de_channel->ch_name);
|
|
|
|
htsmsg_add_u32(m, "start", de->de_start);
|
|
|
|
htsmsg_add_u32(m, "stop", de->de_stop);
|
2009-08-19 19:44:33 +00:00
|
|
|
|
|
|
|
htsmsg_add_s32(m, "start_extra", de->de_start_extra);
|
|
|
|
htsmsg_add_s32(m, "stop_extra", de->de_stop_extra);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
htsmsg_add_str(m, "creator", de->de_creator);
|
|
|
|
|
|
|
|
if(de->de_filename != NULL)
|
|
|
|
htsmsg_add_str(m, "filename", de->de_filename);
|
|
|
|
|
|
|
|
htsmsg_add_str(m, "title", de->de_title);
|
|
|
|
|
|
|
|
if(de->de_desc != NULL)
|
|
|
|
htsmsg_add_str(m, "description", de->de_desc);
|
|
|
|
|
2010-03-17 21:16:57 +00:00
|
|
|
htsmsg_add_str(m, "pri", dvr_val2pri(de->de_pri));
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2010-03-21 10:08:16 +00:00
|
|
|
if(de->de_last_error)
|
|
|
|
htsmsg_add_u32(m, "errorcode", de->de_last_error);
|
|
|
|
|
|
|
|
if(de->de_errors)
|
|
|
|
htsmsg_add_u32(m, "errors", de->de_errors);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
htsmsg_add_u32(m, "noresched", de->de_dont_reschedule);
|
|
|
|
|
2010-03-16 19:54:45 +00:00
|
|
|
if(de->de_autorec != NULL)
|
|
|
|
htsmsg_add_str(m, "autorec", de->de_autorec->dae_id);
|
|
|
|
|
2010-03-16 22:59:10 +00:00
|
|
|
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);
|
|
|
|
|
2008-09-21 18:17:28 +00:00
|
|
|
hts_settings_save(m, "dvr/log/%d", de->de_id);
|
2008-09-17 21:08:17 +00:00
|
|
|
htsmsg_destroy(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_timer_expire(void *aux)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de = aux;
|
2008-09-20 06:06:41 +00:00
|
|
|
dvr_entry_remove(de);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_stop_recording(dvr_entry_t *de, int stopcode)
|
2008-09-17 21:08:17 +00:00
|
|
|
{
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_rec_unsubscribe(de, stopcode);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
de->de_sched_state = DVR_COMPLETED;
|
|
|
|
|
2008-09-20 06:06:41 +00:00
|
|
|
tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\": "
|
|
|
|
"End of program: %s",
|
|
|
|
de->de_title, de->de_channel->ch_name,
|
2010-03-21 10:08:16 +00:00
|
|
|
streaming_code2txt(de->de_last_error) ?: "Program ended");
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
dvr_entry_save(de);
|
2009-09-09 21:37:40 +00:00
|
|
|
htsp_dvr_entry_update(de);
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_entry_notify(de);
|
2008-09-20 06:06:41 +00:00
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
|
2008-09-20 12:59:23 +00:00
|
|
|
de->de_stop + dvr_retention_days * 86400);
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_timer_stop_recording(void *aux)
|
|
|
|
{
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_stop_recording(aux, 0);
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_timer_start_recording(void *aux)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de = aux;
|
|
|
|
|
|
|
|
de->de_sched_state = DVR_RECORDING;
|
2010-03-21 10:08:16 +00:00
|
|
|
de->de_rec_state = DVR_RS_PENDING;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\" recorder starting",
|
|
|
|
de->de_title, de->de_channel->ch_name);
|
|
|
|
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_entry_notify(de);
|
2009-09-09 21:37:40 +00:00
|
|
|
htsp_dvr_entry_update(de);
|
2008-09-20 06:06:41 +00:00
|
|
|
dvr_rec_subscribe(de);
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2009-08-19 19:44:33 +00:00
|
|
|
gtimer_arm_abs(&de->de_timer, dvr_timer_stop_recording, de,
|
|
|
|
de->de_stop + (60 * de->de_stop_extra));
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
dvr_entry_t *
|
|
|
|
dvr_entry_find_by_id(int id)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
LIST_FOREACH(de, &dvrentries, de_global_link)
|
|
|
|
if(de->de_id == id)
|
|
|
|
break;
|
|
|
|
return de;
|
|
|
|
}
|
|
|
|
|
2009-06-21 20:22:10 +00:00
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2009-06-21 20:22:10 +00:00
|
|
|
dvr_entry_t *
|
|
|
|
dvr_entry_find_by_event(event_t *e)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
|
|
|
|
LIST_FOREACH(de, &e->e_channel->ch_dvrs, de_channel_link)
|
|
|
|
if(de->de_start == e->e_start &&
|
|
|
|
de->de_stop == e->e_stop)
|
|
|
|
return de;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
dvr_entry_t *
|
2008-09-17 21:08:17 +00:00
|
|
|
dvr_entry_cancel(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
switch(de->de_sched_state) {
|
|
|
|
case DVR_SCHEDULED:
|
2008-09-20 06:06:41 +00:00
|
|
|
dvr_entry_remove(de);
|
2009-06-21 20:22:10 +00:00
|
|
|
return NULL;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
case DVR_RECORDING:
|
2008-09-20 06:06:41 +00:00
|
|
|
de->de_dont_reschedule = 1;
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_stop_recording(de, SM_CODE_ABORTED);
|
2009-06-21 20:22:10 +00:00
|
|
|
return de;
|
2008-09-17 21:08:17 +00:00
|
|
|
|
|
|
|
case DVR_COMPLETED:
|
2008-09-20 06:06:41 +00:00
|
|
|
dvr_entry_remove(de);
|
2009-06-21 20:22:10 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort();
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-23 19:38:53 +00:00
|
|
|
/**
|
|
|
|
* Unconditionally remove an entry
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_entry_purge(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
if(de->de_sched_state == DVR_RECORDING)
|
2010-03-21 10:08:16 +00:00
|
|
|
dvr_stop_recording(de, SM_CODE_SOURCE_DELETED);
|
2008-09-23 19:38:53 +00:00
|
|
|
|
|
|
|
dvr_entry_remove(de);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_destroy_by_channel(channel_t *ch)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
|
|
|
|
while((de = LIST_FIRST(&ch->ch_dvrs)) != NULL)
|
|
|
|
dvr_entry_purge(de);
|
|
|
|
}
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_init(void)
|
|
|
|
{
|
2008-09-20 12:59:23 +00:00
|
|
|
htsmsg_t *m;
|
|
|
|
char buf[500];
|
|
|
|
const char *homedir;
|
|
|
|
struct stat st;
|
2008-09-21 09:37:35 +00:00
|
|
|
uint32_t u32;
|
2008-09-20 12:59:23 +00:00
|
|
|
|
|
|
|
/* Default settings */
|
|
|
|
|
|
|
|
dvr_retention_days = 31;
|
2008-09-17 21:08:17 +00:00
|
|
|
dvr_format = strdup("matroska");
|
|
|
|
dvr_file_postfix = strdup("mkv");
|
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
/* Override settings with config */
|
|
|
|
|
2008-09-21 18:17:28 +00:00
|
|
|
if((m = hts_settings_load("dvr/config")) != NULL) {
|
2009-08-19 19:44:33 +00:00
|
|
|
|
|
|
|
htsmsg_get_s32(m, "pre-extra-time", &dvr_extra_time_pre);
|
|
|
|
htsmsg_get_s32(m, "post-extra-time", &dvr_extra_time_post);
|
2008-09-20 12:59:23 +00:00
|
|
|
htsmsg_get_u32(m, "retention-days", &dvr_retention_days);
|
|
|
|
tvh_str_set(&dvr_storage, htsmsg_get_str(m, "storage"));
|
|
|
|
|
2008-09-21 09:37:35 +00:00
|
|
|
if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_DIR_PER_DAY;
|
|
|
|
|
|
|
|
if(!htsmsg_get_u32(m, "channel-dir", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_DIR_PER_CHANNEL;
|
|
|
|
|
|
|
|
if(!htsmsg_get_u32(m, "channel-in-title", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_CHANNEL_IN_TITLE;
|
|
|
|
|
|
|
|
if(!htsmsg_get_u32(m, "date-in-title", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_DATE_IN_TITLE;
|
|
|
|
|
|
|
|
if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_TIME_IN_TITLE;
|
2010-03-11 20:23:44 +00:00
|
|
|
|
|
|
|
if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
|
|
|
|
dvr_flags |= DVR_WHITESPACE_IN_TITLE;
|
2010-03-16 22:59:10 +00:00
|
|
|
|
|
|
|
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;
|
2010-03-11 20:23:44 +00:00
|
|
|
|
2008-10-19 15:08:17 +00:00
|
|
|
tvh_str_set(&dvr_postproc, htsmsg_get_str(m, "postproc"));
|
2008-09-21 09:37:35 +00:00
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
htsmsg_destroy(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dvr_storage == NULL) {
|
|
|
|
/* Try to figure out a good place to put them videos */
|
|
|
|
|
|
|
|
homedir = getenv("HOME");
|
|
|
|
|
|
|
|
if(homedir != NULL) {
|
|
|
|
snprintf(buf, sizeof(buf), "%s/Videos", homedir);
|
|
|
|
if(stat(buf, &st) == 0 && S_ISDIR(st.st_mode))
|
|
|
|
dvr_storage = strdup(buf);
|
|
|
|
|
|
|
|
else if(stat(homedir, &st) == 0 && S_ISDIR(st.st_mode))
|
|
|
|
dvr_storage = strdup(homedir);
|
|
|
|
else
|
|
|
|
dvr_storage = strdup(getcwd(buf, sizeof(buf)));
|
|
|
|
}
|
|
|
|
|
2009-06-07 09:27:10 +00:00
|
|
|
tvhlog(LOG_WARNING, "dvr",
|
|
|
|
"Output directory for video recording is not yet configured. "
|
|
|
|
"Defaulting to to \"%s\". "
|
|
|
|
"This can be changed from the web user interface.",
|
|
|
|
dvr_storage);
|
2008-09-20 12:59:23 +00:00
|
|
|
}
|
|
|
|
|
2008-09-23 21:16:59 +00:00
|
|
|
dvr_autorec_init();
|
|
|
|
|
2010-03-16 19:54:45 +00:00
|
|
|
dvr_db_load();
|
2008-09-17 21:08:17 +00:00
|
|
|
}
|
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_save(void)
|
|
|
|
{
|
2009-03-01 16:51:30 +00:00
|
|
|
htsmsg_t *m = htsmsg_create_map();
|
2008-09-20 12:59:23 +00:00
|
|
|
htsmsg_add_str(m, "storage", dvr_storage);
|
|
|
|
htsmsg_add_u32(m, "retention-days", dvr_retention_days);
|
2009-08-19 19:44:33 +00:00
|
|
|
htsmsg_add_u32(m, "pre-extra-time", dvr_extra_time_pre);
|
|
|
|
htsmsg_add_u32(m, "post-extra-time", dvr_extra_time_post);
|
2008-09-21 09:37:35 +00:00
|
|
|
htsmsg_add_u32(m, "day-dir", !!(dvr_flags & DVR_DIR_PER_DAY));
|
|
|
|
htsmsg_add_u32(m, "channel-dir", !!(dvr_flags & DVR_DIR_PER_CHANNEL));
|
|
|
|
htsmsg_add_u32(m, "channel-in-title", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
|
|
|
|
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));
|
2010-03-16 19:54:45 +00:00
|
|
|
htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
|
2010-03-16 22:59:10 +00:00
|
|
|
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));
|
2008-10-19 15:08:17 +00:00
|
|
|
if(dvr_postproc != NULL)
|
|
|
|
htsmsg_add_str(m, "postproc", dvr_postproc);
|
2008-09-20 12:59:23 +00:00
|
|
|
|
2008-09-21 18:17:28 +00:00
|
|
|
hts_settings_save(m, "dvr/config");
|
2008-09-20 12:59:23 +00:00
|
|
|
htsmsg_destroy(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_storage_set(const char *storage)
|
|
|
|
{
|
|
|
|
if(!strcmp(dvr_storage, storage))
|
|
|
|
return;
|
|
|
|
|
|
|
|
tvh_str_set(&dvr_storage, storage);
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
2008-10-19 15:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_postproc_set(const char *postproc)
|
|
|
|
{
|
|
|
|
if(dvr_postproc != NULL && !strcmp(dvr_postproc, postproc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
tvh_str_set(&dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
2008-09-20 12:59:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_retention_set(int days)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
if(days < 1 || dvr_retention_days == days)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dvr_retention_days = days;
|
|
|
|
|
|
|
|
/* Also, rearm all timres */
|
|
|
|
|
|
|
|
LIST_FOREACH(de, &dvrentries, de_global_link)
|
|
|
|
if(de->de_sched_state == DVR_COMPLETED)
|
|
|
|
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
|
|
|
|
de->de_stop + dvr_retention_days * 86400);
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
|
2008-09-21 09:37:35 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_flags_set(int flags)
|
|
|
|
{
|
|
|
|
if(dvr_flags == flags)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dvr_flags = flags;
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-19 19:44:33 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_extra_time_pre_set(int d)
|
|
|
|
{
|
|
|
|
if(dvr_extra_time_pre == d)
|
|
|
|
return;
|
|
|
|
dvr_extra_time_pre = d;
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_extra_time_post_set(int d)
|
|
|
|
{
|
|
|
|
if(dvr_extra_time_post == d)
|
|
|
|
return;
|
|
|
|
dvr_extra_time_post = d;
|
|
|
|
dvr_save();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-17 21:08:17 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dvr_query_add_entry(dvr_query_result_t *dqr, dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
if(dqr->dqr_entries == dqr->dqr_alloced) {
|
|
|
|
/* Need to alloc more space */
|
|
|
|
|
|
|
|
dqr->dqr_alloced = MAX(100, dqr->dqr_alloced * 2);
|
|
|
|
dqr->dqr_array = realloc(dqr->dqr_array,
|
|
|
|
dqr->dqr_alloced * sizeof(dvr_entry_t *));
|
|
|
|
}
|
|
|
|
dqr->dqr_array[dqr->dqr_entries++] = de;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_query(dvr_query_result_t *dqr)
|
|
|
|
{
|
|
|
|
dvr_entry_t *de;
|
|
|
|
|
|
|
|
memset(dqr, 0, sizeof(dvr_query_result_t));
|
|
|
|
|
|
|
|
LIST_FOREACH(de, &dvrentries, de_global_link)
|
|
|
|
dvr_query_add_entry(dqr, de);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_query_free(dvr_query_result_t *dqr)
|
|
|
|
{
|
|
|
|
free(dqr->dqr_array);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting functions
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
dvr_sort_start_descending(const void *A, const void *B)
|
|
|
|
{
|
|
|
|
dvr_entry_t *a = *(dvr_entry_t **)A;
|
|
|
|
dvr_entry_t *b = *(dvr_entry_t **)B;
|
|
|
|
return b->de_start - a->de_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dvr_query_sort(dvr_query_result_t *dqr)
|
|
|
|
{
|
|
|
|
int (*sf)(const void *a, const void *b);
|
|
|
|
|
|
|
|
if(dqr->dqr_array == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sf = dvr_sort_start_descending;
|
|
|
|
qsort(dqr->dqr_array, dqr->dqr_entries, sizeof(dvr_entry_t *), sf);
|
|
|
|
}
|
|
|
|
|
2008-09-24 21:30:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
off_t
|
|
|
|
dvr_get_filesize(dvr_entry_t *de)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if(de->de_filename == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(stat(de->de_filename, &st) != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return st.st_size;
|
|
|
|
}
|
2010-03-17 21:16:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static struct strtab priotab[] = {
|
|
|
|
{ "important", DVR_PRIO_IMPORTANT },
|
|
|
|
{ "high", DVR_PRIO_HIGH },
|
|
|
|
{ "normal", DVR_PRIO_NORMAL },
|
|
|
|
{ "low", DVR_PRIO_LOW },
|
|
|
|
{ "unimportant", DVR_PRIO_UNIMPORTANT },
|
|
|
|
};
|
|
|
|
|
|
|
|
dvr_prio_t
|
|
|
|
dvr_pri2val(const char *s)
|
|
|
|
{
|
|
|
|
return str2val_def(s, priotab, DVR_PRIO_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
dvr_val2pri(dvr_prio_t v)
|
|
|
|
{
|
|
|
|
return val2str(v, priotab) ?: "invalid";
|
|
|
|
}
|