Add tables and web ui editor for auto recording.
No backing logic yet though.
This commit is contained in:
parent
a9f039cf14
commit
ad6ea1b8e1
8 changed files with 385 additions and 4 deletions
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ SRCS = main.c access.c dtable.c tcp.c http.c notify.c epg.c xmltv.c spawn.c
|
|||
SRCS += packet.c streaming.c
|
||||
|
||||
VPATH += dvr
|
||||
SRCS += dvr_db.c dvr_rec.c
|
||||
SRCS += dvr_db.c dvr_rec.c dvr_autorec.c
|
||||
|
||||
SRCS += channels.c subscriptions.c transports.c
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ typedef struct channel {
|
|||
|
||||
struct dvr_entry_list ch_dvrs;
|
||||
|
||||
struct autorec_list ch_autorecs;
|
||||
struct dvr_autorec_entry_list ch_autorecs;
|
||||
|
||||
struct xmltv_channel *ch_xc;
|
||||
LIST_ENTRY(channel) ch_xc_link;
|
||||
|
@ -79,6 +79,8 @@ typedef struct channel_tag {
|
|||
char *ct_comment;
|
||||
char *ct_identifier;
|
||||
struct channel_tag_mapping_list ct_ctms;
|
||||
|
||||
struct dvr_autorec_entry_list ct_autorecs;
|
||||
} channel_tag_t;
|
||||
|
||||
|
||||
|
|
|
@ -126,6 +126,8 @@ void dvr_entry_create_by_event(event_t *e, const char *creator);
|
|||
|
||||
void dvr_init(void);
|
||||
|
||||
void dvr_autorec_init(void);
|
||||
|
||||
void dvr_destroy_by_channel(channel_t *ch);
|
||||
|
||||
void dvr_rec_subscribe(dvr_entry_t *de);
|
||||
|
|
313
dvr/dvr_autorec.c
Normal file
313
dvr/dvr_autorec.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* tvheadend, access control
|
||||
* 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>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "dvr.h"
|
||||
#include "dtable.h"
|
||||
#include "epg.h"
|
||||
|
||||
TAILQ_HEAD(dvr_autorec_entry_queue, dvr_autorec_entry);
|
||||
|
||||
struct dvr_autorec_entry_queue autorec_entries;
|
||||
|
||||
typedef struct dvr_autorec_entry {
|
||||
TAILQ_ENTRY(dvr_autorec_entry) dae_link;
|
||||
char *dae_id;
|
||||
|
||||
int dae_enabled;
|
||||
char *dae_creator;
|
||||
|
||||
char *dae_title;
|
||||
regex_t dae_title_preg;
|
||||
|
||||
epg_content_group_t *dae_ecg;
|
||||
|
||||
channel_t *dae_channel;
|
||||
LIST_ENTRY(dvr_autorec_entry) dae_channel_link;
|
||||
|
||||
channel_tag_t *dae_channel_tag;
|
||||
LIST_ENTRY(dvr_autorec_entry) dae_channel_tag_link;
|
||||
|
||||
} dvr_autorec_entry_t;
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* return 1 if the event 'e' is matched by the autorec rule 'ar'
|
||||
*/
|
||||
static int
|
||||
autorec_cmp(dvr_autorec_entry_t *dae, event_t *e)
|
||||
{
|
||||
channel_tag_mapping_t *ctm;
|
||||
|
||||
if(dae->dae_channel != NULL &&
|
||||
dae->dae_channel != e->e_channel)
|
||||
return 0;
|
||||
|
||||
if(dae->dae_channel_tag != NULL) {
|
||||
LIST_FOREACH(ctm, &dae->dae_channel_tag->ct_ctms, ctm_tag_link)
|
||||
if(ctm->ctm_channel == e->e_channel)
|
||||
break;
|
||||
if(ctm == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if(dae->dae_ecg != NULL) {
|
||||
if(e->e_content_type == NULL ||
|
||||
dae->dae_ecg != e->e_content_type->ect_group)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dae->dae_title != NULL &&
|
||||
regexec(&dae->dae_title_preg, e->e_title, 0, NULL, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static dvr_autorec_entry_t *
|
||||
autorec_entry_find(const char *id, int create)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
char buf[20];
|
||||
static int tally;
|
||||
|
||||
if(id != NULL) {
|
||||
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
|
||||
if(!strcmp(dae->dae_id, id))
|
||||
return dae;
|
||||
}
|
||||
|
||||
if(create == 0)
|
||||
return NULL;
|
||||
|
||||
dae = calloc(1, sizeof(dvr_autorec_entry_t));
|
||||
if(id == NULL) {
|
||||
tally++;
|
||||
snprintf(buf, sizeof(buf), "%d", tally);
|
||||
id = buf;
|
||||
} else {
|
||||
tally = MAX(atoi(id), tally);
|
||||
}
|
||||
|
||||
dae->dae_id = strdup(id);
|
||||
TAILQ_INSERT_TAIL(&autorec_entries, dae, dae_link);
|
||||
return dae;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
autorec_entry_destroy(dvr_autorec_entry_t *dae)
|
||||
{
|
||||
free(dae->dae_id);
|
||||
|
||||
free(dae->dae_creator);
|
||||
|
||||
if(dae->dae_title != NULL) {
|
||||
free(dae->dae_title);
|
||||
regfree(&dae->dae_title_preg);
|
||||
}
|
||||
|
||||
if(dae->dae_channel != NULL)
|
||||
LIST_REMOVE(dae, dae_channel_link);
|
||||
|
||||
if(dae->dae_channel_tag != NULL)
|
||||
LIST_REMOVE(dae, dae_channel_tag_link);
|
||||
|
||||
TAILQ_REMOVE(&autorec_entries, dae, dae_link);
|
||||
free(dae);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
autorec_record_build(dvr_autorec_entry_t *dae)
|
||||
{
|
||||
htsmsg_t *e = htsmsg_create();
|
||||
|
||||
htsmsg_add_str(e, "id", dae->dae_id);
|
||||
htsmsg_add_u32(e, "enabled", !!dae->dae_enabled);
|
||||
htsmsg_add_str(e, "creator", dae->dae_creator ?: "");
|
||||
if(dae->dae_channel)
|
||||
htsmsg_add_str(e, "channel",
|
||||
dae->dae_channel ? dae->dae_channel->ch_name : "");
|
||||
if(dae->dae_channel_tag)
|
||||
htsmsg_add_str(e, "channeltag",
|
||||
dae->dae_channel_tag ? dae->dae_channel_tag->ct_name : "");
|
||||
htsmsg_add_str(e, "title", dae->dae_title ?: "");
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
autorec_record_get_all(void *opaque)
|
||||
{
|
||||
htsmsg_t *r = htsmsg_create_array();
|
||||
dvr_autorec_entry_t *dae;
|
||||
|
||||
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
|
||||
htsmsg_add_msg(r, NULL, autorec_record_build(dae));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
autorec_record_get(void *opaque, const char *id)
|
||||
{
|
||||
dvr_autorec_entry_t *ae;
|
||||
|
||||
if((ae = autorec_entry_find(id, 0)) == NULL)
|
||||
return NULL;
|
||||
return autorec_record_build(ae);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
autorec_record_create(void *opaque)
|
||||
{
|
||||
return autorec_record_build(autorec_entry_find(NULL, 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
||||
int maycreate)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
const char *s;
|
||||
channel_t *ch;
|
||||
channel_tag_t *ct;
|
||||
|
||||
if((dae = autorec_entry_find(id, maycreate)) == NULL)
|
||||
return NULL;
|
||||
|
||||
tvh_str_set(&dae->dae_creator, htsmsg_get_str(values, "creator"));
|
||||
|
||||
if((s = htsmsg_get_str(values, "channel")) != NULL) {
|
||||
if(dae->dae_channel != NULL) {
|
||||
LIST_REMOVE(dae, dae_channel_link);
|
||||
dae->dae_channel = NULL;
|
||||
}
|
||||
if((ch = channel_find_by_name(s, 0)) != NULL) {
|
||||
LIST_INSERT_HEAD(&ch->ch_autorecs, dae, dae_channel_link);
|
||||
dae->dae_channel = ch;
|
||||
}
|
||||
}
|
||||
|
||||
if((s = htsmsg_get_str(values, "title")) != NULL) {
|
||||
if(dae->dae_title != NULL) {
|
||||
free(dae->dae_title);
|
||||
dae->dae_title = NULL;
|
||||
regfree(&dae->dae_title_preg);
|
||||
}
|
||||
|
||||
if(!regcomp(&dae->dae_title_preg, s,
|
||||
REG_ICASE | REG_EXTENDED | REG_NOSUB)) {
|
||||
dae->dae_title = strdup(s);
|
||||
}
|
||||
}
|
||||
|
||||
if((s = htsmsg_get_str(values, "channeltag")) != NULL) {
|
||||
if(dae->dae_channel_tag != NULL) {
|
||||
LIST_REMOVE(dae, dae_channel_tag_link);
|
||||
dae->dae_channel_tag = NULL;
|
||||
}
|
||||
if((ct = channel_tag_find_by_name(s)) != NULL) {
|
||||
LIST_INSERT_HEAD(&ct->ct_autorecs, dae, dae_channel_tag_link);
|
||||
dae->dae_channel_tag = ct;
|
||||
}
|
||||
}
|
||||
|
||||
return autorec_record_build(dae);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
autorec_record_delete(void *opaque, const char *id)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
|
||||
if((dae = autorec_entry_find(id, 0)) == NULL)
|
||||
return -1;
|
||||
autorec_entry_destroy(dae);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const dtable_class_t autorec_dtc = {
|
||||
.dtc_record_get = autorec_record_get,
|
||||
.dtc_record_get_all = autorec_record_get_all,
|
||||
.dtc_record_create = autorec_record_create,
|
||||
.dtc_record_update = autorec_record_update,
|
||||
.dtc_record_delete = autorec_record_delete,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvr_autorec_init(void)
|
||||
{
|
||||
dtable_t *dt;
|
||||
|
||||
TAILQ_INIT(&autorec_entries);
|
||||
dt = dtable_create(&autorec_dtc, "autorec", NULL);
|
||||
dtable_load(dt);
|
||||
}
|
|
@ -518,6 +518,9 @@ dvr_init(void)
|
|||
}
|
||||
|
||||
dvr_db_load();
|
||||
|
||||
dvr_autorec_init();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
2
tvhead.h
2
tvhead.h
|
@ -104,7 +104,7 @@ LIST_HEAD(th_muxstream_list, th_muxstream);
|
|||
LIST_HEAD(th_descrambler_list, th_descrambler);
|
||||
TAILQ_HEAD(th_refpkt_queue, th_refpkt);
|
||||
TAILQ_HEAD(th_muxpkt_queue, th_muxpkt);
|
||||
LIST_HEAD(autorec_list, autorec);
|
||||
LIST_HEAD(dvr_autorec_entry_list, dvr_autorec_entry);
|
||||
TAILQ_HEAD(th_pktref_queue, th_pktref);
|
||||
LIST_HEAD(streaming_target_list, streaming_target);
|
||||
LIST_HEAD(streaming_component_list, streaming_component);
|
||||
|
|
|
@ -185,7 +185,66 @@ tvheadend.dvrlog = function() {
|
|||
}
|
||||
return panel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
tvheadend.autoreceditor = function() {
|
||||
var fm = Ext.form;
|
||||
|
||||
var enabledColumn = new Ext.grid.CheckColumn({
|
||||
header: "Enabled",
|
||||
dataIndex: 'enabled',
|
||||
width: 60
|
||||
});
|
||||
|
||||
var cm = new Ext.grid.ColumnModel([
|
||||
enabledColumn,
|
||||
{
|
||||
header: "Title (Regexp)",
|
||||
dataIndex: 'title',
|
||||
width: 200,
|
||||
editor: new fm.TextField({allowBlank: true})
|
||||
},{
|
||||
header: "Channel",
|
||||
dataIndex: 'channel',
|
||||
editor: new Ext.form.ComboBox({
|
||||
loadingText: 'Loading...',
|
||||
width: 200,
|
||||
displayField:'name',
|
||||
store: tvheadend.channels,
|
||||
mode: 'local',
|
||||
editable: false,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Only include channel...'
|
||||
})
|
||||
},{
|
||||
header: "Channel tag",
|
||||
dataIndex: 'channeltag',
|
||||
editor: new Ext.form.ComboBox({
|
||||
displayField:'name',
|
||||
store: tvheadend.channelTags,
|
||||
mode: 'local',
|
||||
editable: false,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Only include tag...'
|
||||
})
|
||||
},{
|
||||
header: "Creator",
|
||||
dataIndex: 'creator',
|
||||
editor: new fm.TextField({allowBlank: false})
|
||||
}
|
||||
]);
|
||||
|
||||
var rec = Ext.data.Record.create([
|
||||
'enabled','title','channel','channeltag','creator'
|
||||
]);
|
||||
|
||||
return new tvheadend.tableEditor('Automatic Recorder',
|
||||
'autorec', cm, rec,
|
||||
[enabledColumn]);
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -195,7 +254,8 @@ tvheadend.dvr = function() {
|
|||
activeTab:0,
|
||||
autoScroll:true,
|
||||
title: 'Digital Video Recorder',
|
||||
items: [new tvheadend.dvrlog
|
||||
items: [new tvheadend.dvrlog,
|
||||
new tvheadend.autoreceditor
|
||||
]
|
||||
});
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ tvheadend.tableEditor = function(title, dtable, cm, rec, plugins) {
|
|||
fields: rec,
|
||||
url: "tablemgr",
|
||||
autoLoad: true,
|
||||
id: 'id',
|
||||
baseParams: {table: dtable, op: "get"}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue