tvheadend/src/api/api_dvr.c
2014-09-15 20:59:44 +02:00

396 lines
11 KiB
C

/*
* API - DVR
*
* Copyright (C) 2014 Jaroslav Kysela
*
* 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 "tvheadend.h"
#include "dvr/dvr.h"
#include "epg.h"
#include "api.h"
static const char *
api_dvr_config_name( access_t *perm, const char *config_uuid )
{
dvr_config_t *cfg = NULL;
htsmsg_field_t *f;
const char *uuid;
lock_assert(&global_lock);
if (perm->aa_dvrcfgs == NULL)
return config_uuid; /* no change */
config_uuid = config_uuid ?: "";
HTSMSG_FOREACH(f, perm->aa_dvrcfgs) {
uuid = htsmsg_field_get_str(f) ?: "";
if (strcmp(uuid, config_uuid) == 0)
return config_uuid;
if (!cfg)
cfg = dvr_config_find_by_uuid(uuid);
}
if (!cfg && perm->aa_username)
tvhlog(LOG_INFO, "dvr", "User '%s' has no valid dvr config in ACL, using default...", perm->aa_username);
return cfg ? idnode_uuid_as_str(&cfg->dvr_id) : NULL;
}
/*
*
*/
static void
api_dvr_config_grid
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_config_t *cfg;
LIST_FOREACH(cfg, &dvrconfigs, config_link)
if (!idnode_perm((idnode_t *)cfg, perm, NULL))
idnode_set_add(ins, (idnode_t*)cfg, &conf->filter);
}
static int
api_dvr_config_create
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
dvr_config_t *cfg;
htsmsg_t *conf;
const char *s;
if (!(conf = htsmsg_get_map(args, "conf")))
return EINVAL;
if (!(s = htsmsg_get_str(conf, "name")))
return EINVAL;
if (s[0] == '\0')
return EINVAL;
pthread_mutex_lock(&global_lock);
if ((cfg = dvr_config_create(NULL, NULL, conf)))
dvr_config_save(cfg);
pthread_mutex_unlock(&global_lock);
return 0;
}
static int is_dvr_entry_finished(dvr_entry_t *entry)
{
dvr_entry_sched_state_t state = entry->de_sched_state;
return state == DVR_COMPLETED && !entry->de_last_error && dvr_get_filesize(entry) != -1;
}
static int is_dvr_entry_upcoming(dvr_entry_t *entry)
{
dvr_entry_sched_state_t state = entry->de_sched_state;
return state == DVR_RECORDING || state == DVR_SCHEDULED;
}
static int is_dvr_entry_failed(dvr_entry_t *entry)
{
if (is_dvr_entry_finished(entry))
return 0;
if (is_dvr_entry_upcoming(entry))
return 0;
return 1;
}
static void
api_dvr_entry_grid
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_entry_t *de;
LIST_FOREACH(de, &dvrentries, de_global_link)
idnode_set_add(ins, (idnode_t*)de, &conf->filter);
}
static void
api_dvr_entry_grid_upcoming
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_entry_t *de;
LIST_FOREACH(de, &dvrentries, de_global_link)
if (is_dvr_entry_upcoming(de))
idnode_set_add(ins, (idnode_t*)de, &conf->filter);
}
static void
api_dvr_entry_grid_finished
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_entry_t *de;
LIST_FOREACH(de, &dvrentries, de_global_link)
if (is_dvr_entry_finished(de))
idnode_set_add(ins, (idnode_t*)de, &conf->filter);
}
static void
api_dvr_entry_grid_failed
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_entry_t *de;
LIST_FOREACH(de, &dvrentries, de_global_link)
if (is_dvr_entry_failed(de))
idnode_set_add(ins, (idnode_t*)de, &conf->filter);
}
static int
api_dvr_entry_create
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
dvr_entry_t *de;
htsmsg_t *conf;
const char *s1, *s2;
if (!(conf = htsmsg_get_map(args, "conf")))
return EINVAL;
pthread_mutex_lock(&global_lock);
s1 = htsmsg_get_str(conf, "config_name");
s2 = api_dvr_config_name(perm, s1);
if (strcmp(s1 ?: "", s2 ?: ""))
htsmsg_set_str(conf, "config_name", s2 ?: "");
if (perm->aa_representative)
htsmsg_set_str(conf, "creator", perm->aa_representative);
if ((de = dvr_entry_create(NULL, conf)))
dvr_entry_save(de);
pthread_mutex_unlock(&global_lock);
return 0;
}
static htsmsg_t *
api_dvr_entry_create_from_single(htsmsg_t *args)
{
htsmsg_t *entries, *m;
const char *s1, *s2;
if (!(s1 = htsmsg_get_str(args, "config_uuid")))
return NULL;
if (!(s2 = htsmsg_get_str(args, "event_id")))
return NULL;
entries = htsmsg_create_list();
m = htsmsg_create_map();
htsmsg_add_str(m, "config_uuid", s1);
htsmsg_add_str(m, "event_id", s2);
htsmsg_add_msg(entries, NULL, m);
return entries;
}
static int
api_dvr_entry_create_by_event
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
dvr_entry_t *de;
const char *config_uuid;
epg_broadcast_t *e;
htsmsg_t *entries, *entries2 = NULL, *m;
htsmsg_field_t *f;
const char *s;
int count = 0;
if (!(entries = htsmsg_get_list(args, "entries"))) {
entries = entries2 = api_dvr_entry_create_from_single(args);
if (!entries)
return EINVAL;
}
HTSMSG_FOREACH(f, entries) {
if (!(m = htsmsg_get_map_by_field(f))) continue;
if (!(config_uuid = htsmsg_get_str(m, "config_uuid")))
continue;
if (!(s = htsmsg_get_str(m, "event_id")))
continue;
pthread_mutex_lock(&global_lock);
if ((e = epg_broadcast_find_by_id(atoi(s), NULL))) {
de = dvr_entry_create_by_event(api_dvr_config_name(perm, config_uuid),
e, 0, 0, perm->aa_representative,
NULL, DVR_PRIO_NORMAL, 0);
if (de)
dvr_entry_save(de);
}
pthread_mutex_unlock(&global_lock);
count++;
}
htsmsg_destroy(entries2);
return !count ? EINVAL : 0;
}
static void
api_dvr_cancel(access_t *perm, idnode_t *self)
{
dvr_entry_cancel((dvr_entry_t *)self);
}
static int
api_dvr_entry_cancel
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
return api_idnode_handler(perm, args, resp, api_dvr_cancel);
}
static void
api_dvr_autorec_grid
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_autorec_entry_t *dae;
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
idnode_set_add(ins, (idnode_t*)dae, &conf->filter);
}
static int
api_dvr_autorec_create
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
htsmsg_t *conf;
dvr_autorec_entry_t *dae;
if (!(conf = htsmsg_get_map(args, "conf")))
return EINVAL;
if (perm->aa_representative)
htsmsg_set_str(conf, "creator", perm->aa_representative);
pthread_mutex_lock(&global_lock);
dae = dvr_autorec_create(NULL, conf);
if (dae) {
dvr_autorec_save(dae);
dvr_autorec_changed(dae, 1);
}
pthread_mutex_unlock(&global_lock);
return 0;
}
static int
api_dvr_autorec_create_by_series
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
dvr_autorec_entry_t *dae;
epg_broadcast_t *e;
htsmsg_t *entries, *entries2 = NULL, *m;
htsmsg_field_t *f;
const char *config_uuid, *s;
int count = 0;
if (!(entries = htsmsg_get_list(args, "entries"))) {
entries = entries2 = api_dvr_entry_create_from_single(args);
if (!entries)
return EINVAL;
}
HTSMSG_FOREACH(f, entries) {
if (!(m = htsmsg_get_map_by_field(f))) continue;
if (!(config_uuid = htsmsg_get_str(m, "config_uuid")))
continue;
if (!(s = htsmsg_get_str(m, "event_id")))
continue;
pthread_mutex_lock(&global_lock);
if ((e = epg_broadcast_find_by_id(atoi(s), NULL))) {
dae = dvr_autorec_add_series_link(api_dvr_config_name(perm, config_uuid),
e, perm->aa_representative,
"Created from EPG query");
if (dae) {
dvr_autorec_save(dae);
dvr_autorec_changed(dae, 1);
}
}
pthread_mutex_unlock(&global_lock);
count++;
}
htsmsg_destroy(entries2);
return !count ? EINVAL : 0;
}
static void
api_dvr_timerec_grid
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
{
dvr_timerec_entry_t *dte;
TAILQ_FOREACH(dte, &timerec_entries, dte_link)
idnode_set_add(ins, (idnode_t*)dte, &conf->filter);
}
static int
api_dvr_timerec_create
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
htsmsg_t *conf;
dvr_timerec_entry_t *dte;
if (!(conf = htsmsg_get_map(args, "conf")))
return EINVAL;
if (perm->aa_representative)
htsmsg_set_str(conf, "creator", perm->aa_representative);
pthread_mutex_lock(&global_lock);
dte = dvr_timerec_create(NULL, conf);
if (dte) {
dvr_timerec_save(dte);
dvr_timerec_check(dte);
}
pthread_mutex_unlock(&global_lock);
return 0;
}
void api_dvr_init ( void )
{
static api_hook_t ah[] = {
{ "dvr/config/class", ACCESS_RECORDER, api_idnode_class, (void*)&dvr_config_class },
{ "dvr/config/grid", ACCESS_RECORDER, api_idnode_grid, api_dvr_config_grid },
{ "dvr/config/create", ACCESS_ADMIN, api_dvr_config_create, NULL },
{ "dvr/entry/class", ACCESS_RECORDER, api_idnode_class, (void*)&dvr_entry_class },
{ "dvr/entry/grid", ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid },
{ "dvr/entry/grid_upcoming", ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_upcoming },
{ "dvr/entry/grid_finished", ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_finished },
{ "dvr/entry/grid_failed", ACCESS_RECORDER, api_idnode_grid, api_dvr_entry_grid_failed },
{ "dvr/entry/create", ACCESS_RECORDER, api_dvr_entry_create, NULL },
{ "dvr/entry/create_by_event", ACCESS_RECORDER, api_dvr_entry_create_by_event, NULL },
{ "dvr/entry/cancel", ACCESS_RECORDER, api_dvr_entry_cancel, NULL },
{ "dvr/autorec/class", ACCESS_RECORDER, api_idnode_class, (void*)&dvr_autorec_entry_class },
{ "dvr/autorec/grid", ACCESS_RECORDER, api_idnode_grid, api_dvr_autorec_grid },
{ "dvr/autorec/create", ACCESS_RECORDER, api_dvr_autorec_create, NULL },
{ "dvr/autorec/create_by_series", ACCESS_RECORDER, api_dvr_autorec_create_by_series, NULL },
{ "dvr/timerec/class", ACCESS_RECORDER, api_idnode_class, (void*)&dvr_timerec_entry_class },
{ "dvr/timerec/grid", ACCESS_RECORDER, api_idnode_grid, api_dvr_timerec_grid },
{ "dvr/timerec/create", ACCESS_RECORDER, api_dvr_timerec_create, NULL },
{ NULL },
};
api_register_all(ah);
}