From 32664acac912623dfaf52e4e7af7f25d5735be63 Mon Sep 17 00:00:00 2001 From: Glenn-1990 Date: Sat, 13 Sep 2014 21:53:15 +0200 Subject: [PATCH] [htsp] add autorec support --- src/dvr/dvr.h | 14 +++ src/dvr/dvr_autorec.c | 92 +++++++++++++++- src/dvr/dvr_db.c | 2 +- src/htsp_server.c | 244 +++++++++++++++++++++++++++++++++++++----- src/htsp_server.h | 4 + 5 files changed, 325 insertions(+), 31 deletions(-) diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 2f518c50..89d8cd39 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -262,6 +262,10 @@ typedef struct dvr_autorec_entry { int dae_minduration; int dae_maxduration; + int dae_retention; + + time_t dae_start_extra; + time_t dae_stop_extra; } dvr_autorec_entry_t; TAILQ_HEAD(dvr_autorec_entry_queue, dvr_autorec_entry); @@ -428,6 +432,14 @@ int dvr_sort_start_ascending(const void *A, const void *B); dvr_autorec_entry_t * dvr_autorec_create(const char *uuid, htsmsg_t *conf); +dvr_autorec_entry_t* +dvr_autorec_create_htsp(const char *dvr_config_name, const char *title, + channel_t *ch, uint32_t aroundTime, uint32_t days, + time_t start_extra, time_t stop_extra, + dvr_prio_t pri, int retention, + int min_duration, int max_duration, + const char *creator, const char *comment); + dvr_autorec_entry_t * dvr_autorec_add_series_link(const char *dvr_config_name, epg_broadcast_t *event, @@ -452,6 +464,8 @@ void autorec_destroy_by_channel(channel_t *ch, int delconf); void autorec_destroy_by_channel_tag(channel_tag_t *ct, int delconf); +void autorec_destroy_by_id(const char *id, int delconf); + /** * */ diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 38635f20..f15564dc 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -1,6 +1,6 @@ /* * tvheadend, Automatic recordings - * Copyright (C) 2010 Andreas Öman + * Copyright (C) 2010 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 @@ -33,6 +33,7 @@ #include "dvr.h" #include "dtable.h" #include "epg.h" +#include "htsp_server.h" static int dvr_autorec_in_init = 0; @@ -179,6 +180,58 @@ dvr_autorec_create(const char *uuid, htsmsg_t *conf) idnode_load(&dae->dae_id, conf); + htsp_autorec_entry_add(dae); + + return dae; +} + + +dvr_autorec_entry_t* +dvr_autorec_create_htsp(const char *dvr_config_name, const char *title, + channel_t *ch, uint32_t aroundTime, uint32_t weekdays, + time_t start_extra, time_t stop_extra, + dvr_prio_t pri, int retention, + int min_duration, int max_duration, + const char *creator, const char *comment) +{ + dvr_autorec_entry_t *dae; + htsmsg_t *conf, *days; + + conf = htsmsg_create_map(); + days = htsmsg_create_list(); + + htsmsg_add_u32(conf, "enabled", 1); + htsmsg_add_u32(conf, "retention", retention); + htsmsg_add_u32(conf, "pri", pri); + htsmsg_add_u32(conf, "minduration", min_duration); + htsmsg_add_u32(conf, "maxduration", max_duration); + htsmsg_add_s64(conf, "start_extra", start_extra); + htsmsg_add_s64(conf, "stop_extra", stop_extra); + htsmsg_add_str(conf, "title", title); + htsmsg_add_str(conf, "config_name", dvr_config_name ?: ""); + htsmsg_add_str(conf, "creator", creator ?: ""); + htsmsg_add_str(conf, "comment", comment ?: ""); + + if (aroundTime) + htsmsg_add_u32(conf, "start", (aroundTime-1)); + if (ch) + htsmsg_add_str(conf, "channel", idnode_uuid_as_str(&ch->ch_id)); + + int i; + for (i = 0; i < 7; i++) + if (weekdays & (1 << i)) + htsmsg_add_u32(days, NULL, i + 1); + + htsmsg_add_msg(conf, "weekdays", days); + + dae = dvr_autorec_create(NULL, conf); + htsmsg_destroy(conf); + + if (dae) { + dvr_autorec_save(dae); + dvr_autorec_changed(dae, 1); + } + return dae; } @@ -222,6 +275,8 @@ autorec_entry_destroy(dvr_autorec_entry_t *dae, int delconf) if (delconf) hts_settings_remove("dvr/autorec/%s", idnode_uuid_as_str(&dae->dae_id)); + htsp_autorec_entry_delete(dae); + TAILQ_REMOVE(&autorec_entries, dae, dae_link); idnode_unlink(&dae->dae_id); @@ -739,6 +794,20 @@ const idclass_t dvr_autorec_entry_class = { .get = dvr_autorec_entry_class_start_get, .list = dvr_autorec_entry_class_time_list, }, + { + .type = PT_TIME, + .id = "start_extra", + .name = "Extra Start Time", + .off = offsetof(dvr_autorec_entry_t, dae_start_extra), + .opts = PO_DURATION, + }, + { + .type = PT_TIME, + .id = "stop_extra", + .name = "Extra Stop Time", + .off = offsetof(dvr_autorec_entry_t, dae_stop_extra), + .opts = PO_DURATION, + }, { .type = PT_U32, .islist = 1, @@ -778,6 +847,12 @@ const idclass_t dvr_autorec_entry_class = { .def.i = DVR_PRIO_NORMAL, .off = offsetof(dvr_autorec_entry_t, dae_pri), }, + { + .type = PT_INT, + .id = "retention", + .name = "Retention", + .off = offsetof(dvr_autorec_entry_t, dae_retention), + }, { .type = PT_STR, .id = "config_name", @@ -920,6 +995,8 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge) dvr_entry_create_by_autorec(e, dae); } } + + htsp_autorec_entry_update(dae); } @@ -951,3 +1028,16 @@ autorec_destroy_by_channel_tag(channel_tag_t *ct, int delconf) dvr_autorec_save(dae); } } + +/* + * + */ +void +autorec_destroy_by_id(const char *id, int delconf) +{ + dvr_autorec_entry_t *dae; + dae = dvr_autorec_find_by_uuid(id); + + if (dae) + autorec_entry_destroy(dae, delconf); +} diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 4ad1b5f1..2ff6d94a 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -616,7 +616,7 @@ dvr_entry_create_by_autorec(epg_broadcast_t *e, dvr_autorec_entry_t *dae) } else { snprintf(buf, sizeof(buf), "Auto recording"); } - dvr_entry_create_by_event(dae->dae_config_name, e, 0, 0, buf, dae, dae->dae_pri, 0); + dvr_entry_create_by_event(dae->dae_config_name, e, dae->dae_start_extra, dae->dae_stop_extra, buf, dae, dae->dae_pri, dae->dae_retention); } /** diff --git a/src/htsp_server.c b/src/htsp_server.c index 94c33d25..49942faf 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -663,6 +663,9 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method) if (de->de_bcast) htsmsg_add_u32(out, "eventId", de->de_bcast->id); + if (de->de_autorec) + htsmsg_add_str(out, "autorecId", idnode_uuid_as_str(&de->de_autorec->dae_id)); + htsmsg_add_s64(out, "start", de->de_start); htsmsg_add_s64(out, "stop", de->de_stop); htsmsg_add_s64(out, "startExtra", dvr_entry_get_extra_time_pre(de)); @@ -712,6 +715,36 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method) return out; } +/** + * + */ +static htsmsg_t * +htsp_build_autorecentry(dvr_autorec_entry_t *dae, const char *method) +{ + htsmsg_t *out = htsmsg_create_map(); + + htsmsg_add_str(out, "id", idnode_uuid_as_str(&dae->dae_id)); + htsmsg_add_u32(out, "enabled", dae->dae_enabled); + htsmsg_add_u32(out, "maxDuration", dae->dae_maxduration); + htsmsg_add_u32(out, "minDuration", dae->dae_minduration); + htsmsg_add_u32(out, "retention", dae->dae_retention); + htsmsg_add_u32(out, "daysOfWeek", dae->dae_weekdays); + htsmsg_add_u32(out, "approxTime", dae->dae_start); + htsmsg_add_u32(out, "priority", dae->dae_pri); + htsmsg_add_s64(out, "startExtra", dae->dae_start_extra); + htsmsg_add_s64(out, "stopExtra", dae->dae_stop_extra); + + if(dae->dae_title) + htsmsg_add_str(out, "title", dae->dae_title); + + if(dae->dae_channel) + htsmsg_add_u32(out, "channel", channel_get_id(dae->dae_channel)); + + htsmsg_add_str(out, "method", method); + + return out; +} + /** * */ @@ -922,6 +955,7 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in) channel_t *ch; channel_tag_t *ct; dvr_entry_t *de; + dvr_autorec_entry_t *dae; htsmsg_t *m; uint32_t epg = 0; int64_t lastUpdate = 0; @@ -961,6 +995,10 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in) if(ct->ct_enabled && !ct->ct_internal) htsp_send_message(htsp, htsp_build_tag(ct, "tagUpdate", 1), NULL); + /* Send all autorecs */ + TAILQ_FOREACH(dae, &autorec_entries, dae_link) + htsp_send_message(htsp, htsp_build_autorecentry(dae, "autorecEntryAdd"), NULL); + /* Send all DVR entries */ LIST_FOREACH(de, &dvrentries, de_global_link) if (htsp_user_access_channel(htsp,de->de_channel)) @@ -1362,6 +1400,100 @@ htsp_method_deleteDvrEntry(htsp_connection_t *htsp, htsmsg_t *in) return out; } +/** + * add a Dvr autorec entry + */ +static htsmsg_t * +htsp_method_addAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in) +{ + htsmsg_t *out; + dvr_autorec_entry_t *dae; + const char *dvr_config_name, *title, *creator, *comment; + int64_t start_extra, stop_extra; + uint32_t u32, days_of_week, priority, approx_time, + min_duration, max_duration, retention; + channel_t *ch = NULL; + + /* Options */ + if(!(title = htsmsg_get_str(in, "title"))) + return htsp_error("Invalid arguments"); + if(!(dvr_config_name = htsmsg_get_str(in, "configName"))) + dvr_config_name = ""; + if(!htsmsg_get_u32(in, "channelId", &u32)) + ch = channel_find_by_id(u32); + if(htsmsg_get_u32(in, "maxDuration", &max_duration)) + max_duration = 0; // 0 = any + if(htsmsg_get_u32(in, "minDuration", &min_duration)) + min_duration = 0; // 0 = any + if(htsmsg_get_u32(in, "retention", &retention)) + retention = 0; // 0 = dvr config + if(htsmsg_get_u32(in, "daysOfWeek", &days_of_week)) + days_of_week = 0x7f; // all days + if(htsmsg_get_u32(in, "priority", &priority)) + priority = DVR_PRIO_NORMAL; + if(htsmsg_get_u32(in, "approxTime", &approx_time)) + approx_time = 0; + else + approx_time++; + if(htsmsg_get_s64(in, "startExtra", &start_extra)) + start_extra = 0; // 0 = dvr config + if(htsmsg_get_s64(in, "stopExtra", &stop_extra)) + stop_extra = 0; // 0 = dvr config + if (!(creator = htsmsg_get_str(in, "creator")) || !*creator) + creator = htsp->htsp_username ?: "anonymous"; + if (!(comment = htsmsg_get_str(in, "comment"))) + comment = ""; + + /* Check access */ + if (!htsp_user_access_channel(htsp, ch)) + return htsp_error("User does not have access"); + + dae = dvr_autorec_create_htsp(dvr_config_name, title, ch, approx_time, days_of_week, + start_extra, stop_extra, priority, retention, min_duration, max_duration, creator, comment); + + /* create response */ + out = htsmsg_create_map(); + + if (dae) { + htsmsg_add_str(out, "id", idnode_uuid_as_str(&dae->dae_id)); + htsmsg_add_u32(out, "success", 1); + } + else { + htsmsg_add_str(out, "error", "Could not add autorec entry"); + htsmsg_add_u32(out, "success", 0); + } + return out; +} + +/** + * delete a Dvr autorec entry + */ +static htsmsg_t * +htsp_method_deleteAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in) +{ + htsmsg_t *out; + const char *daeId; + dvr_autorec_entry_t *dae; + + if (!(daeId = htsmsg_get_str(in, "id"))) + return htsp_error("Missing argument 'id'"); + + if((dae = dvr_autorec_find_by_uuid(daeId)) == NULL) + return htsp_error("id not found"); + + /* Check access */ + if (!htsp_user_access_channel(htsp, dae->dae_channel)) + return htsp_error("User does not have access"); + + autorec_destroy_by_id(daeId, 1); + + /* create response */ + out = htsmsg_create_map(); + htsmsg_add_u32(out, "success", 1); + + return out; +} + /** * Return cutpoint data for a recording (if present). * @@ -1957,37 +2089,39 @@ struct { htsmsg_t *(*fn)(htsp_connection_t *htsp, htsmsg_t *in); int privmask; } htsp_methods[] = { - { "hello", htsp_method_hello, ACCESS_ANONYMOUS}, - { "authenticate", htsp_method_authenticate, ACCESS_ANONYMOUS}, - { "getDiskSpace", htsp_method_getDiskSpace, ACCESS_STREAMING}, - { "getSysTime", htsp_method_getSysTime, ACCESS_STREAMING}, - { "enableAsyncMetadata", htsp_method_async, ACCESS_STREAMING}, - { "getEvent", htsp_method_getEvent, ACCESS_STREAMING}, - { "getEvents", htsp_method_getEvents, ACCESS_STREAMING}, - { "epgQuery", htsp_method_epgQuery, ACCESS_STREAMING}, - { "getEpgObject", htsp_method_getEpgObject, ACCESS_STREAMING}, - { "addDvrEntry", htsp_method_addDvrEntry, ACCESS_RECORDER}, - { "updateDvrEntry", htsp_method_updateDvrEntry, ACCESS_RECORDER}, - { "cancelDvrEntry", htsp_method_cancelDvrEntry, ACCESS_RECORDER}, - { "deleteDvrEntry", htsp_method_deleteDvrEntry, ACCESS_RECORDER}, - { "getDvrCutpoints", htsp_method_getDvrCutpoints, ACCESS_RECORDER}, - { "getTicket", htsp_method_getTicket, ACCESS_STREAMING}, - { "subscribe", htsp_method_subscribe, ACCESS_STREAMING}, - { "unsubscribe", htsp_method_unsubscribe, ACCESS_STREAMING}, - { "subscriptionChangeWeight", htsp_method_change_weight, ACCESS_STREAMING}, - { "subscriptionSeek", htsp_method_skip, ACCESS_STREAMING}, - { "subscriptionSkip", htsp_method_skip, ACCESS_STREAMING}, - { "subscriptionSpeed", htsp_method_speed, ACCESS_STREAMING}, - { "subscriptionLive", htsp_method_live, ACCESS_STREAMING}, - { "subscriptionFilterStream", htsp_method_filter_stream, ACCESS_STREAMING}, + { "hello", htsp_method_hello, ACCESS_ANONYMOUS}, + { "authenticate", htsp_method_authenticate, ACCESS_ANONYMOUS}, + { "getDiskSpace", htsp_method_getDiskSpace, ACCESS_STREAMING}, + { "getSysTime", htsp_method_getSysTime, ACCESS_STREAMING}, + { "enableAsyncMetadata", htsp_method_async, ACCESS_STREAMING}, + { "getEvent", htsp_method_getEvent, ACCESS_STREAMING}, + { "getEvents", htsp_method_getEvents, ACCESS_STREAMING}, + { "epgQuery", htsp_method_epgQuery, ACCESS_STREAMING}, + { "getEpgObject", htsp_method_getEpgObject, ACCESS_STREAMING}, + { "addDvrEntry", htsp_method_addDvrEntry, ACCESS_RECORDER}, + { "updateDvrEntry", htsp_method_updateDvrEntry, ACCESS_RECORDER}, + { "cancelDvrEntry", htsp_method_cancelDvrEntry, ACCESS_RECORDER}, + { "deleteDvrEntry", htsp_method_deleteDvrEntry, ACCESS_RECORDER}, + { "addAutorecEntry", htsp_method_addAutorecEntry, ACCESS_RECORDER}, + { "deleteAutorecEntry", htsp_method_deleteAutorecEntry, ACCESS_RECORDER}, + { "getDvrCutpoints", htsp_method_getDvrCutpoints, ACCESS_RECORDER}, + { "getTicket", htsp_method_getTicket, ACCESS_STREAMING}, + { "subscribe", htsp_method_subscribe, ACCESS_STREAMING}, + { "unsubscribe", htsp_method_unsubscribe, ACCESS_STREAMING}, + { "subscriptionChangeWeight", htsp_method_change_weight, ACCESS_STREAMING}, + { "subscriptionSeek", htsp_method_skip, ACCESS_STREAMING}, + { "subscriptionSkip", htsp_method_skip, ACCESS_STREAMING}, + { "subscriptionSpeed", htsp_method_speed, ACCESS_STREAMING}, + { "subscriptionLive", htsp_method_live, ACCESS_STREAMING}, + { "subscriptionFilterStream", htsp_method_filter_stream, ACCESS_STREAMING}, #if ENABLE_LIBAV - { "getCodecs", htsp_method_getCodecs, ACCESS_STREAMING}, + { "getCodecs", htsp_method_getCodecs, ACCESS_STREAMING}, #endif - { "fileOpen", htsp_method_file_open, ACCESS_RECORDER}, - { "fileRead", htsp_method_file_read, ACCESS_RECORDER}, - { "fileClose", htsp_method_file_close, ACCESS_RECORDER}, - { "fileStat", htsp_method_file_stat, ACCESS_RECORDER}, - { "fileSeek", htsp_method_file_seek, ACCESS_RECORDER}, + { "fileOpen", htsp_method_file_open, ACCESS_RECORDER}, + { "fileRead", htsp_method_file_read, ACCESS_RECORDER}, + { "fileClose", htsp_method_file_close, ACCESS_RECORDER}, + { "fileStat", htsp_method_file_stat, ACCESS_RECORDER}, + { "fileSeek", htsp_method_file_seek, ACCESS_RECORDER}, }; #define NUM_METHODS (sizeof(htsp_methods) / sizeof(htsp_methods[0])) @@ -2550,6 +2684,58 @@ htsp_dvr_entry_delete(dvr_entry_t *de) htsp_async_send(m, HTSP_ASYNC_ON); } +/** + * Called when a autorec entry is updated/added + */ +static void +_htsp_autorec_entry_update(dvr_autorec_entry_t *dae, const char *method, htsmsg_t *msg) +{ + htsp_connection_t *htsp; + LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) { + if (htsp->htsp_async_mode & HTSP_ASYNC_ON) { + if (dae->dae_channel == NULL || htsp_user_access_channel(htsp, dae->dae_channel)) { + htsmsg_t *m = msg ? htsmsg_copy(msg) + : htsp_build_autorecentry(dae, method); + htsp_send_message(htsp, m, NULL); + } + } + } + htsmsg_destroy(msg); +} + +/** + * Called from dvr_autorec.c when a autorec entry is added + */ +void +htsp_autorec_entry_add(dvr_autorec_entry_t *dae) +{ + _htsp_autorec_entry_update(dae, "autorecEntryAdd", NULL); +} + +/** + * Called from dvr_autorec.c when a autorec entry is updated + */ +void +htsp_autorec_entry_update(dvr_autorec_entry_t *dae) +{ + _htsp_autorec_entry_update(dae, "autorecEntryUpdate", NULL); +} + +/** + * Called from dvr_autorec.c when a autorec entry is deleted + */ +void +htsp_autorec_entry_delete(dvr_autorec_entry_t *dae) +{ + if(dae == NULL) + return; + + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_str(m, "id", idnode_uuid_as_str(&dae->dae_id)); + htsmsg_add_str(m, "method", "autorecEntryDelete"); + htsp_async_send(m, HTSP_ASYNC_ON); +} + /** * Called when a event entry is updated/added */ diff --git a/src/htsp_server.h b/src/htsp_server.h index 53cc4967..f6a0fd03 100644 --- a/src/htsp_server.h +++ b/src/htsp_server.h @@ -40,6 +40,10 @@ void htsp_dvr_entry_add(dvr_entry_t *de); void htsp_dvr_entry_update(dvr_entry_t *de); void htsp_dvr_entry_delete(dvr_entry_t *de); +void htsp_autorec_entry_add(dvr_autorec_entry_t *dae); +void htsp_autorec_entry_update(dvr_autorec_entry_t *dae); +void htsp_autorec_entry_delete(dvr_autorec_entry_t *dae); + void htsp_event_add(epg_broadcast_t *ebc); void htsp_event_update(epg_broadcast_t *ebc); void htsp_event_delete(epg_broadcast_t *ebc);