]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Add tables and web ui editor for auto recording.
authorAndreas Öman <andreas@lonelycoder.com>
Tue, 23 Sep 2008 21:16:59 +0000 (21:16 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Tue, 23 Sep 2008 21:16:59 +0000 (21:16 +0000)
No backing logic yet though.

Makefile
channels.h
dvr/dvr.h
dvr/dvr_autorec.c [new file with mode: 0644]
dvr/dvr_db.c
tvhead.h
webui/static/app/dvr.js
webui/static/app/tableeditor.js

index fcdcb2970e672cc45d498f0f2c29fb81fa60d781..be9503c34780e14e4599c89f52cbde928e666ac0 100644 (file)
--- a/Makefile
+++ b/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
 
index 9c9ae3e2adfe5658994a6fdf23fa16da04866217..1d294c3c3ca9483065fdf7fb606f457399eb2350 100644 (file)
@@ -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;
 
 
index aa2ce3e7cf4782a00435e602a7a08dc2b6abf654..9dc817e34d244726a1faacc3f60f0b9ea85b233b 100644 (file)
--- a/dvr/dvr.h
+++ b/dvr/dvr.h
@@ -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);
diff --git a/dvr/dvr_autorec.c b/dvr/dvr_autorec.c
new file mode 100644 (file)
index 0000000..f1cce68
--- /dev/null
@@ -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);
+}
index e91f916e78d641b991a64987fdd03b5516308900..e251dc2861b8913a0a6538207c7188b3649a44e8 100644 (file)
@@ -518,6 +518,9 @@ dvr_init(void)
   }
 
   dvr_db_load();
+
+  dvr_autorec_init();
+
 }
 
 /**
index d1a06ed4ac5da059e37d53dacad08aa64ccfb2d6..9e091cdafb4bffca2725ac93cfaf97f912381448 100644 (file)
--- a/tvhead.h
+++ b/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);
index 286fb3c08de5f0d930225b15c79499c99f5da011..7f2ca7910745669625c7730abb780bb01fce7dce 100644 (file)
@@ -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
               ]
     });
 
index bcfa061c3eaf036a69431302fc1ddc9b004c925f..aeceec597de9d3cd88a121f97b592b59c6574283 100644 (file)
@@ -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"}
     });