* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sys/mman.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "epg.h"
#include "dvr/dvr.h"
#include "htsp.h"
+#include "htsmsg_binary.h"
#define EPG_MAX_AGE 86400
}
-/*
+/**
*
*/
-void
-epg_init(void)
+static int
+epg_event_create_by_msg(htsmsg_t *c, time_t now)
{
- event_t *e;
- int injected = 0;
- int created = 0;
- uint32_t id = 0;
+ channel_t *ch;
+ event_t *e = NULL;
+ uint32_t ch_id = 0;
+ uint32_t e_start = 0;
+ uint32_t e_stop = 0;
+ int e_dvb_id = 0, v;
+ const char *s;
- htsmsg_t *l, *c;
- htsmsg_field_t *f;
+ // Now create the event
+ if(htsmsg_get_u32(c, "ch_id", &ch_id))
+ return 0;
- if((l = hts_settings_load("epg")) == NULL)
- return;
-
- HTSMSG_FOREACH(f, l) {
- if((c = htsmsg_get_map_by_field(f)) == NULL)
- continue;
+ if((ch = channel_find_by_identifier(ch_id)) == NULL)
+ return 0;
- e = epg_event_create_by_msg(c, &created);
- htsmsg_get_u32(c, "id", &id);
+ if(htsmsg_get_u32(c, "start", &e_start))
+ return 0;
- hts_settings_remove("epg/%d", id);
+ if(htsmsg_get_u32(c, "stop", &e_stop))
+ return 0;
- if(created)
- injected++;
- }
- htsmsg_destroy(l);
+ if(e_stop < now)
+ return 0;
- tvhlog(LOG_INFO, "epg", "Injected %d epg events.", injected);
-}
+ if(htsmsg_get_s32(c, "dvb_id", &e_dvb_id))
+ e_dvb_id = -1;
-/*
+ e = epg_event_create(ch, e_start, e_stop, e_dvb_id, NULL);
+
+ if((s = htsmsg_get_str(c, "title")) != NULL)
+ epg_event_set_title(e, s);
+
+ if((s = htsmsg_get_str(c, "desc")) != NULL)
+ epg_event_set_desc(e, s);
+
+ if(!htsmsg_get_s32(c, "season", &v))
+ e->e_episode.ee_season = v;
+
+ if(!htsmsg_get_s32(c, "episode", &v))
+ e->e_episode.ee_episode = v;
+
+ if(!htsmsg_get_s32(c, "part", &v))
+ e->e_episode.ee_part = v;
+
+ if((s = htsmsg_get_str(c, "epname")) != NULL)
+ tvh_str_set(&e->e_episode.ee_onscreen, s);
+
+ return 1;
+}
+
+
+/**
*
*/
-event_t *
-epg_event_create_by_msg(htsmsg_t *c, int *created)
+static void
+epg_load(void)
{
- channel_t *ch;
- event_t *e = NULL;
- uint32_t ch_id = 0;
- uint32_t e_start = 0;
- uint32_t e_stop = 0;
- int e_dvb_id = 0;
- const char *e_title, *e_desc;
+ struct stat st;
+ int fd = hts_settings_open_file(0, "epgdb");
+ time_t now;
+ int created = 0;
- if (created != NULL)
- *created = 0;
+ time(&now);
- // Now create the event
- htsmsg_get_u32(c, "ch_id", &ch_id);
- ch = channel_find_by_identifier(ch_id);
- if (ch == NULL)
- tvhlog(LOG_DEBUG, "epg", "Cannot find this channel, skipping...");
- else {
- htsmsg_get_u32(c, "start", &e_start);
- htsmsg_get_u32(c, "stop", &e_stop);
- htsmsg_get_s32(c, "dvb_id", &e_dvb_id);
+ if(fd == -1)
+ return;
- e = epg_event_create(ch, e_start, e_stop, e_dvb_id, created);
+ if(fstat(fd, &st)) {
+ close(fd);
+ return;
+ }
+ uint8_t *mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if(mem == MAP_FAILED) {
+ close(fd);
+ return;
+ }
+ const uint8_t *rp = mem;
+ size_t remain = st.st_size;
- int changed = 0;
+ while(remain > 4) {
+ int msglen = (rp[0] << 24) | (rp[1] << 16) | (rp[2] << 8) | rp[3];
+ remain -= 4;
+ rp += 4;
- e_title = htsmsg_get_str(c, "title");
- if (e_title != NULL)
- changed |= epg_event_set_title(e, e_title);
+ if(msglen > remain) {
+ tvhlog(LOG_ERR, "EPG", "Malformed EPG database, skipping some data");
+ break;
+ }
+ htsmsg_t *m = htsmsg_binary_deserialize(rp, msglen, NULL);
- e_desc = htsmsg_get_str(c, "title");
- if (e_desc != NULL)
- changed |= epg_event_set_title(e, e_desc);
+ created += epg_event_create_by_msg(m, now);
- if(changed)
- epg_event_updated(e);
- }
+ htsmsg_destroy(m);
+ rp += msglen;
+ remain -= msglen;
+ }
- return e;
+ munmap(mem, st.st_size);
+ close(fd);
+ tvhlog(LOG_NOTICE, "EPG", "Injected %d event from disk database", created);
}
-/*
+/**
+ *
+ */
+void
+epg_init(void)
+{
+ epg_load();
+}
+
+
+/**
* Save the epg on disk
*/
void
epg_save(void)
{
event_t *e;
- int saved = 0;
-
+ int num_saved = 0;
+ size_t msglen;
+ void *msgdata;
channel_t *ch;
+ int fd = hts_settings_open_file(1, "epgdb");
+
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
RB_FOREACH(e, &ch->ch_epg_events, e_channel_link) {
- if((e->e_start) && (e->e_stop)) {
- htsmsg_t *m = htsmsg_create_map();
- htsmsg_add_u32(m, "id", saved);
- htsmsg_add_u32(m, "start", e->e_start);
- htsmsg_add_u32(m, "stop", e->e_stop);
- if (e->e_title != NULL)
- htsmsg_add_str(m, "title", e->e_title);
-
- if (e->e_desc != NULL)
- htsmsg_add_str(m, "desc", e->e_desc);
- htsmsg_add_u32(m, "ch_id", ch->ch_id);
- htsmsg_add_s32(m, "dvb_id", e->e_dvb_id);
-
- hts_settings_save(m, "epg/%d", saved);
-
- saved++;
+ if(!e->e_start || !e->e_stop)
+ continue;
+
+ htsmsg_t *m = htsmsg_create_map();
+ htsmsg_add_u32(m, "ch_id", ch->ch_id);
+ htsmsg_add_u32(m, "start", e->e_start);
+ htsmsg_add_u32(m, "stop", e->e_stop);
+ if(e->e_title != NULL)
+ htsmsg_add_str(m, "title", e->e_title);
+ if(e->e_desc != NULL)
+ htsmsg_add_str(m, "desc", e->e_desc);
+ if(e->e_dvb_id)
+ htsmsg_add_u32(m, "dvb_id", e->e_dvb_id);
+
+ if(e->e_episode.ee_season)
+ htsmsg_add_u32(m, "season", e->e_episode.ee_season);
+
+ if(e->e_episode.ee_episode)
+ htsmsg_add_u32(m, "episode", e->e_episode.ee_episode);
+
+ if(e->e_episode.ee_part)
+ htsmsg_add_u32(m, "part", e->e_episode.ee_part);
+
+ if(e->e_episode.ee_onscreen)
+ htsmsg_add_str(m, "epname", e->e_episode.ee_onscreen);
+
+
+ int r = htsmsg_binary_serialize(m, &msgdata, &msglen, 0x10000);
+ htsmsg_destroy(m);
+
+ if(!r) {
+ ssize_t written = write(fd, msgdata, msglen);
+ int err = errno;
+ free(msgdata);
+ if(written != msglen) {
+ tvhlog(LOG_DEBUG, "epg", "Failed to store EPG on disk -- %s",
+ strerror(err));
+ close(fd);
+ hts_settings_remove("epgdb");
+ return;
+ }
}
+ num_saved++;
}
}
- tvhlog(LOG_DEBUG, "epg", "Wrote epg data for %d events", saved);
+ close(fd);
+ tvhlog(LOG_DEBUG, "EPG", "Stored EPG data for %d events on disk", num_saved);
}