813 lines
21 KiB
C
813 lines
21 KiB
C
/*
|
|
* Humax EPG Tool
|
|
* by af123, 2011
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include "lint.h"
|
|
#include <sqlite3.h>
|
|
#include "epgsql.h"
|
|
#include "sys/stat.h"
|
|
#include <stdlib.h>
|
|
|
|
int debug = 0;
|
|
const char *version = "1.8";
|
|
unsigned long sysopts = 0;
|
|
unsigned long filterflags = 0;
|
|
|
|
int
|
|
syntax()
|
|
{
|
|
fprintf(stderr, "Humax Foxsat EPG Tool v%s, by adrianf36, 2011-2016, MofTot 2018-20.\n", version);
|
|
fprintf(stderr, "based on the Humax (T2) EPG Tool from af123 v1.0.2, 2011.\n\n");
|
|
|
|
fprintf(stderr,
|
|
"Syntax: epg [options] [filters] <command>...\n\n");
|
|
fprintf(stderr,
|
|
" Options:\n"
|
|
" -b Brief output.\n"
|
|
" -d[level] Set debug level.\n"
|
|
" -f<file> Specify alternate EPG data file.\n"
|
|
" -h Show help text.\n"
|
|
" -p Parsable output.\n"
|
|
"\n"
|
|
);
|
|
fprintf(stderr,
|
|
" Filters: (can be specified multiple times, all must be true)\n"
|
|
" -C<CRID> Show only events with this CRID.\n"
|
|
" -D<descriptor type> Show only selected descriptor type.\n"
|
|
" -E<event id> Show only selected event.\n"
|
|
" -R<SCRID> Show only events with this Series ID.\n"
|
|
" -S<service id> Show only selected service.\n"
|
|
" -T<content type> Show only selected content types.\n"
|
|
" -@<unix timestamp> Show only programmes at time.\n"
|
|
"\n"
|
|
);
|
|
fprintf(stderr,
|
|
" Commands:\n"
|
|
" dump Show a parsed summary of the EPG.\n"
|
|
" dumpraw Show raw data from the EPG.\n"
|
|
" dumpsql Process the EPG file into a Sqlite Database\n"
|
|
" dumpsqlcont As 'dumpsql' but run continuously\n"
|
|
" Check for updated data every hour and process if necessary\n"
|
|
);
|
|
fprintf(stderr,
|
|
" now Show what is currently on.\n"
|
|
" parse Parse the EPG, no output.\n"
|
|
" search <text> Search programme names for text.\n"
|
|
" searchall <text> "
|
|
"Search programme names/descriptions for text.\n"
|
|
);
|
|
fprintf(stderr, "\n");
|
|
return 0;
|
|
}
|
|
|
|
#define DECOMPRESS(str, len) \
|
|
if (str && *(str) == 0x1f) uncompress_epg(&(str), &(len))
|
|
|
|
unsigned int NeedToProcess (char * epgFile)
|
|
{
|
|
struct stat epgstat;
|
|
unsigned int FileTS;
|
|
unsigned int DBTS;
|
|
FILE * fp;
|
|
|
|
/* Get the timestamp of the epg file to be processed */
|
|
if ((fp = fopen(epgFile, "r"))) {
|
|
if (!stat(epgFile, &epgstat))
|
|
{
|
|
FileTS = (unsigned int) (epgstat.st_mtime);
|
|
} else {
|
|
fprintf(stderr, "Error getting epg file modified date\n");
|
|
return 0;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Input file (%s) does not exist!\n", epgFile);
|
|
return 0;
|
|
}
|
|
|
|
/* Get the timestamp of the last file processed from the DB */
|
|
GetFileTimestamp(&DBTS);
|
|
|
|
/*
|
|
printf("File Timestamp : %i\n", FileTS);
|
|
printf("DB Timestamp : %i\n", DBTS);
|
|
*/
|
|
if (FileTS==DBTS)
|
|
return 0;
|
|
else
|
|
return FileTS;
|
|
}
|
|
|
|
void SwapEPGFiles()
|
|
{
|
|
/*
|
|
Having built the new EPG file as epgnew.db delete the old one
|
|
and replace it with the new one. Handle the case where the old
|
|
one can't be deleted because it's being accessed
|
|
|
|
First thing make sure that the size of the new file looks sensible.
|
|
Expect this to be > 10MB ..... usually it's about 12MB
|
|
*/
|
|
|
|
struct stat epgstat;
|
|
off_t fsize;
|
|
FILE * fp;
|
|
|
|
if ((fp = fopen("/opt/epg/epgnew.db", "r"))) {
|
|
if (!stat("/opt/epg/epgnew.db", &epgstat))
|
|
{
|
|
fsize = epgstat.st_size;
|
|
if (fsize > (10 * 1024 * 1024)) {
|
|
while (remove("/opt/epg/epg.db") == -1)
|
|
{
|
|
sleep(5);
|
|
}
|
|
|
|
while (rename("/opt/epg/epgnew.db", "/opt/epg/epg.db") != 0)
|
|
{
|
|
sleep(5);
|
|
}
|
|
} else {
|
|
/* epgnew.db is smaller than we expected and is probably incomplete.
|
|
Delete it and output a warning.
|
|
*/
|
|
fprintf(stderr, "Error. epgnew.db file size too small. Probably corrupt.\n");
|
|
remove("/opt/epg/epgnew.db");
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Error getting epgnew.db file size\n");
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Can't open epgnew.db\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
pass(struct epg *epg __attribute__((unused)),
|
|
struct section *s __attribute__((unused)),
|
|
struct data *d __attribute__((unused)),
|
|
struct descriptor **ds __attribute__((unused)),
|
|
void *var __attribute__((unused)))
|
|
{
|
|
/* Do nothing. */
|
|
}
|
|
|
|
void
|
|
dumpraw(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
dump_section(s);
|
|
dump_data(d);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
dump_descriptor(ds[PARSER_SHORT_EVENT], 1);
|
|
if (ds[PARSER_USER_DEFINED])
|
|
dump_descriptor(ds[PARSER_USER_DEFINED], 1);
|
|
if (ds[PARSER_CONTENT])
|
|
dump_descriptor(ds[PARSER_CONTENT], 1);
|
|
if (ds[PARSER_CRID_EVENT])
|
|
dump_descriptor(ds[PARSER_CRID_EVENT], 1);
|
|
if (ds[PARSER_CRID_SERIES])
|
|
dump_descriptor(ds[PARSER_CRID_SERIES], 1);
|
|
if (ds[PARSER_CRID_REC])
|
|
dump_descriptor(ds[PARSER_CRID_REC], 1);
|
|
}
|
|
|
|
/* Strings should all be safe now the huffman module is in place... */
|
|
#define safeprintf printf
|
|
|
|
void EscapeChars(char ** InString, unsigned int *Len)
|
|
{
|
|
/* Escape String for inserting into SQLite */
|
|
/* Replace single quote ' with two single quotes '' */
|
|
char * new;
|
|
unsigned int i,j;
|
|
int charcount=0;
|
|
char * originalstring;
|
|
|
|
originalstring=*InString;
|
|
if (strchr(*InString, '\'')!=NULL) {
|
|
/* at least one ' character - process string */
|
|
/* count them so we know how much space to allocate */
|
|
for (i=0; i<*Len; i++) {
|
|
if (originalstring[i]==0x27) {
|
|
charcount++;
|
|
}
|
|
}
|
|
new = (char *) malloc(sizeof(char) * (*Len + charcount + 1));
|
|
j=0;
|
|
for (i=0; i<*Len; i++) {
|
|
new[j++]=originalstring[i];
|
|
if (originalstring[i]==0x27)
|
|
new[j++]=0x27;
|
|
}
|
|
new[j]='\0';
|
|
|
|
free(*InString);
|
|
*InString = new;
|
|
*Len = strlen(new);
|
|
}
|
|
}
|
|
|
|
void
|
|
dumpsql(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var)
|
|
{
|
|
time_t tm;
|
|
char SQLStatement[5000];
|
|
sqlite3 * db = (sqlite3 *)var;
|
|
int rc;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen);
|
|
EscapeChars(&d77->content.d77.name, &d77->content.d77.namelen);
|
|
EscapeChars(&d77->content.d77.text, &d77->content.d77.textlen);
|
|
}
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d = ds[PARSER_USER_DEFINED];
|
|
DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen);
|
|
EscapeChars(&d->content.d137.warning, &d->content.d137.warninglen);
|
|
}
|
|
|
|
/* service_id, event_id, start, duration, encrypted, name, text
|
|
* warning, content code, content type,
|
|
* event CRID, series CRID, rec CRID
|
|
*/
|
|
sprintf(SQLStatement,"insert into epg (serviceid, eventid, starttime, duration, encrypted, name,"\
|
|
"descr, warning, contentcode, contenttype, ECRID, SCRID, RCRID) values (");
|
|
sprintf(SQLStatement, "%s%d,%d,%ld,%d,%d,", SQLStatement,
|
|
s->service_id, d->event_id, tm,
|
|
d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec,
|
|
d->u1.u.free_CA_mode);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
sprintf(SQLStatement,"%s'%.*s',", SQLStatement, d77->content.d77.namelen, d77->content.d77.name);
|
|
sprintf(SQLStatement,"%s'%.*s',", SQLStatement, d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s'','',",SQLStatement);
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
EscapeChars(&d137->content.d137.warning, &d137->content.d137.warninglen);
|
|
sprintf(SQLStatement,"%s'%.*s',", SQLStatement, d137->content.d137.warninglen, d137->content.d137.warning);
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s'',",SQLStatement);
|
|
|
|
if (ds[PARSER_CONTENT])
|
|
{
|
|
sprintf(SQLStatement,"%s%d,", SQLStatement, ds[PARSER_CONTENT]->content.d84.level1);
|
|
sprintf(SQLStatement,"%s'%s',", SQLStatement, content_type(ds[PARSER_CONTENT]));
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s0,'',",SQLStatement);
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_EVENT];
|
|
EscapeChars(&d->content.d118.crids[0].crid, &d->content.d118.crids[0].cridlen);
|
|
sprintf(SQLStatement,"%s'%.*s',", SQLStatement, d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s'',",SQLStatement);
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_SERIES];
|
|
EscapeChars(&d->content.d118.crids[0].crid, &d->content.d118.crids[0].cridlen);
|
|
sprintf(SQLStatement,"%s'%.*s',", SQLStatement, d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s'',",SQLStatement);
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_REC];
|
|
EscapeChars(&d->content.d118.crids[0].crid, &d->content.d118.crids[0].cridlen);
|
|
sprintf(SQLStatement,"%s'%.*s'", SQLStatement, d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
sprintf(SQLStatement,"%s''",SQLStatement);
|
|
|
|
sprintf(SQLStatement,"%s)",SQLStatement);
|
|
rc = ExecSQLStatement(SQLStatement, db);
|
|
return;
|
|
}
|
|
|
|
void dosqldump(char * epgpath,struct epgfilter *filter, int Continuous)
|
|
{
|
|
sqlite3 * db;
|
|
int rc;
|
|
unsigned int FileTS;
|
|
char SQL [500] = {0};
|
|
|
|
if (Continuous==1) {
|
|
while (1) {
|
|
FileTS = NeedToProcess(epgpath);
|
|
if (FileTS !=0) {
|
|
/* Delete any old epgnew SQLite files before trying to open a new one */
|
|
/* Don't worry about error handling - just need to make sure they're gone! */
|
|
remove("/opt/epg/epgnew.db");
|
|
remove("/opt/epg/epgnew.db-journal");
|
|
rc = OpenCreateDB("/opt/epg/epgnew.db", &db);
|
|
|
|
rc = ExecSQLStatement("pragma journal_mode = off;", db);
|
|
rc = ExecSQLStatement("pragma synchronous = off;", db);
|
|
|
|
InitDB("/opt/epg/epgDBinit.sql", db);
|
|
|
|
rc = ExecSQLStatement("BEGIN;", db);
|
|
|
|
parse(epgpath, dumpsql, (void *)db, filter);
|
|
|
|
rc = ExecSQLStatement("COMMIT;", db);
|
|
|
|
copy_freesat_to_non_freesat(db);
|
|
|
|
sprintf(SQL, "replace into epgtimestamp (lastfileprocessed) values (%i);", FileTS);
|
|
rc = ExecSQLStatement("Delete from epgtimestamp;", db);
|
|
rc = ExecSQLStatement(SQL, db);
|
|
|
|
if (db != NULL) CloseDB(db);
|
|
SwapEPGFiles();
|
|
}
|
|
|
|
sleep(3600);
|
|
}
|
|
} else {
|
|
|
|
FileTS = NeedToProcess(epgpath);
|
|
|
|
if (FileTS != 0) {
|
|
|
|
/* Delete any old epgnew SQLite files before trying to open a new one */
|
|
/* Don't worry about error handling - just need to make sure they're gone! */
|
|
remove("/opt/epg/epgnew.db");
|
|
remove("/opt/epg/epgnew.db-journal");
|
|
rc = OpenCreateDB("/opt/epg/epgnew.db", &db);
|
|
|
|
InitDB("/opt/epg/epgDBinit.sql", db);
|
|
|
|
rc = ExecSQLStatement("BEGIN;", db);
|
|
|
|
parse(epgpath, dumpsql, (void *)db, filter);
|
|
|
|
rc = ExecSQLStatement("COMMIT;", db);
|
|
|
|
copy_freesat_to_non_freesat(db);
|
|
|
|
sprintf(SQL, "replace into epgtimestamp (lastfileprocessed) values (%i);", FileTS);
|
|
rc = ExecSQLStatement("Delete from epgtimestamp;", db);
|
|
rc = ExecSQLStatement(SQL, db);
|
|
|
|
if (db != NULL) CloseDB(db);
|
|
SwapEPGFiles();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
dump(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var __attribute__((unused)))
|
|
{
|
|
time_t tm;
|
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen);
|
|
}
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d = ds[PARSER_USER_DEFINED];
|
|
DECOMPRESS(d->content.d137.warning, d->content.d137.warninglen);
|
|
}
|
|
|
|
if (sysopts & SYSOPT_PARSABLE)
|
|
{
|
|
/* service_id, event_id, start, duration, encrypted, name, text
|
|
* warning, content code, content type,
|
|
* event CRID, series CRID, rec CRID
|
|
*/
|
|
printf("%d\t%d\t%ld\t%d\t%d\t",
|
|
s->service_id, d->event_id, tm,
|
|
d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec,
|
|
d->u1.u.free_CA_mode);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("%.*s\t",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("%.*s\t",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
else
|
|
printf("\t\t");
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("%.*s\t", d137->content.d137.warninglen,
|
|
d137->content.d137.warning);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CONTENT])
|
|
{
|
|
printf("%d\t", ds[PARSER_CONTENT]->content.d84.level1);
|
|
printf("%s\t", content_type(ds[PARSER_CONTENT]));
|
|
}
|
|
else
|
|
printf("\t\t");
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_EVENT];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_SERIES];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d = ds[PARSER_CRID_REC];
|
|
printf("%.*s\t", d->content.d118.crids[0].cridlen,
|
|
d->content.d118.crids[0].crid);
|
|
}
|
|
else
|
|
printf("\t");
|
|
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
printf("----------------------------------------------------------\n");
|
|
|
|
if (sysopts & SYSOPT_BRIEF)
|
|
{
|
|
safeprintf("%d/%d: %s+%d\n",
|
|
s->service_id, d->event_id, ctime_nl(&tm),
|
|
d->dur_hour * 3600 + d->dur_min * 60 + d->dur_sec);
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("Name:%.*s\n",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("Text:%.*s\n",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("Warning:%.*s\n",
|
|
d137->content.d137.warninglen,
|
|
d137->content.d137.warning);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
printf("%30s: %d\n", "Service ID", s->service_id);
|
|
printf("%30s: %d\n", "Event ID", d->event_id);
|
|
|
|
printf("%30s: %#x %d:%02d:%02d (%s)\n", "start_date",
|
|
d->start_date, d->start_hour, d->start_min, d->start_sec,
|
|
ctime_nl(&tm));
|
|
|
|
printf("%30s: %d:%02d:%02d\n", "duration",
|
|
d->dur_hour, d->dur_min, d->dur_sec);
|
|
|
|
printf("%30s: %d\n", "encrypted", d->u1.u.free_CA_mode);
|
|
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
safeprintf("%30s: %.*s\n", "Name",
|
|
d77->content.d77.namelen, d77->content.d77.name);
|
|
safeprintf("%30s: %.*s\n", "Text",
|
|
d77->content.d77.textlen, d77->content.d77.text);
|
|
}
|
|
|
|
if (ds[PARSER_USER_DEFINED])
|
|
{
|
|
struct descriptor *d137 = ds[PARSER_USER_DEFINED];
|
|
|
|
safeprintf("%30s: %.*s\n", "Warning",
|
|
d137->content.d137.warninglen, d137->content.d137.warning);
|
|
}
|
|
|
|
if (ds[PARSER_CONTENT])
|
|
printf("%30s: %s (%d)\n", "Content Type",
|
|
content_type(ds[PARSER_CONTENT]),
|
|
ds[PARSER_CONTENT]->content.d84.level1);
|
|
|
|
if (ds[PARSER_CRID_EVENT])
|
|
printf("%30s: %.*s\n", "Event CRID",
|
|
ds[PARSER_CRID_EVENT]->content.d118.crids[0].cridlen,
|
|
ds[PARSER_CRID_EVENT]->content.d118.crids[0].crid);
|
|
|
|
if (ds[PARSER_CRID_SERIES])
|
|
printf("%30s: %.*s\n", "Series CRID",
|
|
ds[PARSER_CRID_SERIES]->content.d118.crids[0].cridlen,
|
|
ds[PARSER_CRID_SERIES]->content.d118.crids[0].crid);
|
|
|
|
if (ds[PARSER_CRID_REC])
|
|
{
|
|
struct descriptor *d118 = ds[PARSER_CRID_REC];
|
|
int i;
|
|
|
|
for (i = 0; i < d118->content.d118.i; i++)
|
|
{
|
|
struct crid *crid = &d118->content.d118.crids[i];
|
|
|
|
printf("%30s: %.*s\n", "Recommended CRID",
|
|
crid->cridlen, crid->crid);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
copy_freesat_to_non_freesat(sqlite3 * db)
|
|
{
|
|
int rc;
|
|
|
|
ExecSQLStatement(
|
|
"attach database '/opt/webif/plugin/epg/epgsettings.db' as epgsettings",
|
|
db
|
|
);
|
|
|
|
ExecSQLStatement("BEGIN;", db);
|
|
|
|
rc = ExecSQLStatementRowCount(
|
|
"insert into epg "
|
|
"select epgmappings.nonfreesatserviceid, "
|
|
"eventid, "
|
|
"starttime, "
|
|
"duration, "
|
|
"encrypted, "
|
|
"name, "
|
|
"descr, "
|
|
"warning, "
|
|
"contentcode, "
|
|
"contenttype, "
|
|
"ECRID, "
|
|
"SCRID, "
|
|
"RCRID "
|
|
"from epgsettings.epgmappings join epg on epg.serviceid = epgsettings.epgmappings.freesatserviceid "
|
|
"except "
|
|
"select epg.* "
|
|
"from epgsettings.epgmappings join epg on epg.serviceid = epgsettings.epgmappings.freesatserviceid",
|
|
db
|
|
);
|
|
|
|
ExecSQLStatement("COMMIT;", db);
|
|
|
|
printf("%d EPG event(s) copied from Freesat to non-Freesat\n", rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
search(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var)
|
|
{
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
|
|
if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name,
|
|
(char *)var))
|
|
dump(epg, s, d, ds, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
searchall(struct epg *epg __attribute__((unused)),
|
|
struct section *s, struct data *d, struct descriptor **ds,
|
|
void *var)
|
|
{
|
|
if (ds[PARSER_SHORT_EVENT])
|
|
{
|
|
struct descriptor *d77 = ds[PARSER_SHORT_EVENT];
|
|
|
|
DECOMPRESS(d77->content.d77.name, d77->content.d77.namelen);
|
|
DECOMPRESS(d77->content.d77.text, d77->content.d77.textlen);
|
|
|
|
if (strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.name,
|
|
(char *)var) ||
|
|
strcasestr(ds[PARSER_SHORT_EVENT]->content.d77.text,
|
|
(char *)var))
|
|
dump(epg, s, d, ds, NULL);
|
|
}
|
|
}
|
|
|
|
#define GETOPTOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc > 1) \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (*cp != '\0' && isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
#define GETOPTINTOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc > 1 && atoi(argv[1]) > 0) \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (*cp != '\0' && isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
#define GETOPT \
|
|
do { \
|
|
if (*++cp == '\0' && argc < 2) \
|
|
{ \
|
|
fprintf(stderr, \
|
|
"No argument supplied for -%c\n", opt); \
|
|
exit(1); \
|
|
} \
|
|
else if (*cp == '\0') \
|
|
{ \
|
|
argc--, argv++; \
|
|
cp = argv[0]; \
|
|
} \
|
|
while (isspace((int)*cp)) \
|
|
cp++; \
|
|
} while (0)
|
|
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
char *epgpath = DEFAULT_EPG_FILE;
|
|
struct epgfilter *filter = NULL;
|
|
char *cp;
|
|
|
|
argc--, argv++;
|
|
while (argc > 0 && *argv[0] == '-')
|
|
{
|
|
for (cp = &argv[0][1]; *cp; cp++)
|
|
{
|
|
char opt;
|
|
switch (opt = *cp)
|
|
{
|
|
case 'b':
|
|
sysopts |= SYSOPT_BRIEF;
|
|
break;
|
|
|
|
case 'd':
|
|
GETOPTINTOPT;
|
|
if (*cp == '\0')
|
|
debug = 1;
|
|
else
|
|
debug = atoi(cp);
|
|
goto nextopt;
|
|
|
|
case 'f':
|
|
GETOPT;
|
|
epgpath = strdup(cp);
|
|
goto nextopt;
|
|
|
|
case 'h':
|
|
return syntax();
|
|
|
|
case 'p':
|
|
sysopts |= SYSOPT_PARSABLE;
|
|
break;
|
|
|
|
/* Filters */
|
|
case '@':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_TIMESTAMP,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'C':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_CRID,
|
|
0, 0, cp, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'D':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_DESCRIPTOR,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'E':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_EVENT,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'S':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_SERVICE,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'R':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_SCRID,
|
|
0, 0, cp, FT_EQUAL);
|
|
goto nextopt;
|
|
|
|
case 'T':
|
|
GETOPT;
|
|
add_epgfilter(&filter, FILTER_CONTENT,
|
|
atoi(cp), 0, NULL, FT_EQUAL);
|
|
goto nextopt;
|
|
}
|
|
}
|
|
nextopt:
|
|
argc--, argv++;
|
|
}
|
|
|
|
if (argc < 1)
|
|
return syntax();
|
|
|
|
if (!strcmp(argv[0], "dump"))
|
|
parse(epgpath, dump, NULL, filter);
|
|
else if (!strcmp(argv[0], "parse"))
|
|
parse(epgpath, pass, NULL, filter);
|
|
else if (!strcmp(argv[0], "dumpraw"))
|
|
parse(epgpath, dumpraw, NULL, filter);
|
|
else if (!strcmp(argv[0], "dumpsql"))
|
|
dosqldump(epgpath, filter, 0);
|
|
else if (!strcmp(argv[0], "now"))
|
|
{
|
|
time_t tm;
|
|
|
|
time(&tm);
|
|
add_epgfilter(&filter, FILTER_TIMESTAMP, tm, 0, NULL, FT_EQUAL);
|
|
parse(epgpath, dump, NULL, filter);
|
|
}
|
|
else if (!strcmp(argv[0], "search") && argc > 1)
|
|
parse(epgpath, search, (void *)argv[1], filter);
|
|
else if (!strcmp(argv[0], "searchall") && argc > 1)
|
|
parse(epgpath, searchall, (void *)argv[1], filter);
|
|
else if (!strcmp(argv[0], "dumpsqlcont"))
|
|
{
|
|
dosqldump(epgpath, filter, 1);
|
|
|
|
}
|
|
else
|
|
syntax();
|
|
|
|
return 0;
|
|
}
|