19#define RUNNINGSTATUSTIMEOUT 30
20#define EPGDATAWRITEDELTA 600
33 unsigned int Stream, Type;
70 esyslog(
"ERROR: out of memory");
102 Stream == 2 && (
components[i].type < 5) == (Type < 5)
250 char vpsbuf[64] =
"";
281 switch (Content & 0xF0) {
283 switch (Content & 0x0F) {
285 case 0x00:
return tr(
"Content$Movie/Drama");
286 case 0x01:
return tr(
"Content$Detective/Thriller");
287 case 0x02:
return tr(
"Content$Adventure/Western/War");
288 case 0x03:
return tr(
"Content$Science Fiction/Fantasy/Horror");
289 case 0x04:
return tr(
"Content$Comedy");
290 case 0x05:
return tr(
"Content$Soap/Melodrama/Folkloric");
291 case 0x06:
return tr(
"Content$Romance");
292 case 0x07:
return tr(
"Content$Serious/Classical/Religious/Historical Movie/Drama");
293 case 0x08:
return tr(
"Content$Adult Movie/Drama");
297 switch (Content & 0x0F) {
299 case 0x00:
return tr(
"Content$News/Current Affairs");
300 case 0x01:
return tr(
"Content$News/Weather Report");
301 case 0x02:
return tr(
"Content$News Magazine");
302 case 0x03:
return tr(
"Content$Documentary");
303 case 0x04:
return tr(
"Content$Discussion/Inverview/Debate");
307 switch (Content & 0x0F) {
309 case 0x00:
return tr(
"Content$Show/Game Show");
310 case 0x01:
return tr(
"Content$Game Show/Quiz/Contest");
311 case 0x02:
return tr(
"Content$Variety Show");
312 case 0x03:
return tr(
"Content$Talk Show");
316 switch (Content & 0x0F) {
318 case 0x00:
return tr(
"Content$Sports");
319 case 0x01:
return tr(
"Content$Special Event");
320 case 0x02:
return tr(
"Content$Sport Magazine");
321 case 0x03:
return tr(
"Content$Football/Soccer");
322 case 0x04:
return tr(
"Content$Tennis/Squash");
323 case 0x05:
return tr(
"Content$Team Sports");
324 case 0x06:
return tr(
"Content$Athletics");
325 case 0x07:
return tr(
"Content$Motor Sport");
326 case 0x08:
return tr(
"Content$Water Sport");
327 case 0x09:
return tr(
"Content$Winter Sports");
328 case 0x0A:
return tr(
"Content$Equestrian");
329 case 0x0B:
return tr(
"Content$Martial Sports");
333 switch (Content & 0x0F) {
335 case 0x00:
return tr(
"Content$Children's/Youth Programme");
336 case 0x01:
return tr(
"Content$Pre-school Children's Programme");
337 case 0x02:
return tr(
"Content$Entertainment Programme for 6 to 14");
338 case 0x03:
return tr(
"Content$Entertainment Programme for 10 to 16");
339 case 0x04:
return tr(
"Content$Informational/Educational/School Programme");
340 case 0x05:
return tr(
"Content$Cartoons/Puppets");
344 switch (Content & 0x0F) {
346 case 0x00:
return tr(
"Content$Music/Ballet/Dance");
347 case 0x01:
return tr(
"Content$Rock/Pop");
348 case 0x02:
return tr(
"Content$Serious/Classical Music");
349 case 0x03:
return tr(
"Content$Folk/Tradional Music");
350 case 0x04:
return tr(
"Content$Jazz");
351 case 0x05:
return tr(
"Content$Musical/Opera");
352 case 0x06:
return tr(
"Content$Ballet");
356 switch (Content & 0x0F) {
358 case 0x00:
return tr(
"Content$Arts/Culture");
359 case 0x01:
return tr(
"Content$Performing Arts");
360 case 0x02:
return tr(
"Content$Fine Arts");
361 case 0x03:
return tr(
"Content$Religion");
362 case 0x04:
return tr(
"Content$Popular Culture/Traditional Arts");
363 case 0x05:
return tr(
"Content$Literature");
364 case 0x06:
return tr(
"Content$Film/Cinema");
365 case 0x07:
return tr(
"Content$Experimental Film/Video");
366 case 0x08:
return tr(
"Content$Broadcasting/Press");
367 case 0x09:
return tr(
"Content$New Media");
368 case 0x0A:
return tr(
"Content$Arts/Culture Magazine");
369 case 0x0B:
return tr(
"Content$Fashion");
373 switch (Content & 0x0F) {
375 case 0x00:
return tr(
"Content$Social/Political/Economics");
376 case 0x01:
return tr(
"Content$Magazine/Report/Documentary");
377 case 0x02:
return tr(
"Content$Economics/Social Advisory");
378 case 0x03:
return tr(
"Content$Remarkable People");
382 switch (Content & 0x0F) {
384 case 0x00:
return tr(
"Content$Education/Science/Factual");
385 case 0x01:
return tr(
"Content$Nature/Animals/Environment");
386 case 0x02:
return tr(
"Content$Technology/Natural Sciences");
387 case 0x03:
return tr(
"Content$Medicine/Physiology/Psychology");
388 case 0x04:
return tr(
"Content$Foreign Countries/Expeditions");
389 case 0x05:
return tr(
"Content$Social/Spiritual Sciences");
390 case 0x06:
return tr(
"Content$Further Education");
391 case 0x07:
return tr(
"Content$Languages");
395 switch (Content & 0x0F) {
397 case 0x00:
return tr(
"Content$Leisure/Hobbies");
398 case 0x01:
return tr(
"Content$Tourism/Travel");
399 case 0x02:
return tr(
"Content$Handicraft");
400 case 0x03:
return tr(
"Content$Motoring");
401 case 0x04:
return tr(
"Content$Fitness & Health");
402 case 0x05:
return tr(
"Content$Cooking");
403 case 0x06:
return tr(
"Content$Advertisement/Shopping");
404 case 0x07:
return tr(
"Content$Gardening");
408 switch (Content & 0x0F) {
409 case 0x00:
return tr(
"Content$Original Language");
410 case 0x01:
return tr(
"Content$Black & White");
411 case 0x02:
return tr(
"Content$Unpublished");
412 case 0x03:
return tr(
"Content$Live Broadcast");
447 strftime(buf,
sizeof(buf),
"%d.%m. %R", localtime_r(&
vps, &tm_r));
456 fprintf(f,
"%sT %s\n", Prefix,
title);
458 fprintf(f,
"%sS %s\n", Prefix,
shortText);
465 fprintf(f,
"%sG", Prefix);
475 fprintf(f,
"%sX %s\n", Prefix, *p->
ToString());
479 fprintf(f,
"%sV %jd\n", Prefix, intmax_t(
vps));
482 fprintf(f,
"%s@ %s\n", Prefix,
aux);
486 fprintf(f,
"%se\n", Prefix);
505 int c = strtol(t, &tail, 16);
506 if (0x00 < c && c <= 0xFF) {
521 case 'V':
SetVps(atol(t));
526 default:
esyslog(
"ERROR: unexpected tag while reading EPG data: %s", s);
538 while ((s = ReadLine.
Read(f)) != NULL) {
542 case 'E':
if (!Event) {
549 if (n >= 3 && n <= 5) {
568 case 'e':
if (Event && !Event->
Title())
574 default:
if (Event && !Event->
Parse(s)) {
575 esyslog(
"ERROR: EPG data problem in line %d", Line);
580 esyslog(
"ERROR: unexpected end of file while reading EPG data");
585#define MAXEPGBUGFIXSTATS 13
586#define MAXEPGBUGFIXCHANS 100
602 for (; i < p->
n; i++) {
614 static time_t LastReport = 0;
615 time_t now = time(NULL);
616 if (now - LastReport > 3600 || Force) {
619 struct tm *ptm = localtime_r(&now, &tm_r);
620 if (ptm->tm_hour != 5)
625 bool GotHits =
false;
628 const char *delim =
" ";
631 bool PrintedStats =
false;
635 for (
int c = 0; c < p->
n; c++) {
638 dsyslog(
"=====================");
639 dsyslog(
"EPG bugfix statistics");
640 dsyslog(
"=====================");
641 dsyslog(
"IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED");
642 dsyslog(
"CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEvent::FixEpgBugs()");
643 dsyslog(
"IN VDR/epg.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!");
644 dsyslog(
"=====================");
649 q += snprintf(q,
sizeof(buffer) - (q - buffer),
"%-3d %-4d", i, p->
hits);
652 q += snprintf(q,
sizeof(buffer) - (q - buffer),
"%s%s", delim, Channel->Name());
654 if (q - buffer > 80) {
655 q += snprintf(q,
sizeof(buffer) - (q - buffer),
"%s...", delim);
666 dsyslog(
"=====================");
677 if (l == 2 && *p == 0xC2)
679 if (*p == 0x86 || *p == 0x87 || *p == 0x0D) {
680 memmove(s, p + 1, len - l + 1);
713 const char *delim =
"\".";
714 char *e = strstr(p + 1, delim);
717 char *s = strdup(p + 1);
718 char *d = strdup(e + strlen(delim));
783#define MAX_USEFUL_EPISODE_LENGTH 40
847 case 0x08: p->
description = strdup(
">16:9");
break;
849 case 0x0D: p->
description = strdup(
"HD 4:3");
break;
853 case 0x0F: p->
description = strdup(
"HD 16:9");
break;
855 case 0x10: p->
description = strdup(
"HD >16:9");
break;
874 case 0x05: p->
description = strdup(
"Dolby Digital");
break;
891 if (
char *p = strstr(
shortText,
"\\n")) {
953 if ((TableId & 0xF0) == 0x50)
1004 time_t now = time(NULL);
1006 if (p->StartTime() <= now)
1008 else if (p->StartTime() > now + 3600)
1022 time_t now = time(NULL);
1031#if DEPRECATED_SCHEDULE_GET_EVENT
1058 time_t delta = INT_MAX;
1060 time_t dt = Time - p->StartTime();
1061 if (dt >= 0 && dt < delta && p->EndTime() >= Time) {
1075 p->SetRunningStatus(RunningStatus, Channel);
1104 p->SetVersion(0xFF);
1124 if (SegmentStart > 0 && SegmentEnd > 0) {
1131 if ((p->
TableID() > 0x4E || TableID == 0x4E) && (p->
TableID() != TableID || p->
Version() != Version)) {
1165 fprintf(f,
"%sC %s %s\n", Prefix, *Channel->GetChannelID().ToString(), Channel->Name());
1188 default:
esyslog(
"ERROR: unknown DumpMode %d (%s %d)", DumpMode, __FUNCTION__, __LINE__);
1190 fprintf(f,
"%sc\n", Prefix);
1200 while ((s = ReadLine.
Read(f)) != NULL) {
1204 char *p = strchr(s,
' ');
1217 esyslog(
"ERROR: invalid channel ID: %s", s);
1223 esyslog(
"ERROR: unexpected tag in line %d while reading EPG data: %s", Line, s);
1239 virtual void Action(
void);
1247:
cThread(
"epg data writer", true)
1263 time_t now = time(NULL);
1264 for (
cSchedule *p = Schedules->First(); p; p = Schedules->
Next(p))
1307 time_t now = time(NULL);
1320 for (
cSchedule *Schedule = Schedules->First(); Schedule; Schedule = Schedules->
Next(Schedule))
1321 Schedule->ResetVersions();
1339 for (
const cSchedule *p = Schedules->First(); p; p = Schedules->
Next(p))
1340 p->Dump(Channels, f, Prefix, DumpMode, AtTime);
1350 bool OwnFile = f == NULL;
1369 for (
cChannel *Channel = Channels->First(); Channel; Channel = Channels->
Next(Channel)) {
1370 if (
const cSchedule *Schedule = Channel->schedule) {
1371 if (!Schedule->ChannelID().Valid())
1372 Channel->schedule = NULL;
1374 Schedules->GetSchedule(Channel);
1395 if (p->ChannelID() == ChannelID)
1411 Channel->
schedule = &DummySchedule;
1412 if (Channel->
schedule == &DummySchedule && AddIfMissing) {
1451 if (eh->IgnoreChannel(Channel))
1460 if (eh->HandleEitEvent(Schedule, EitEvent, TableID, Version))
1469 if (eh->HandledExternally(Channel))
1478 if (eh->IsUpdate(EventID, StartTime, TableID, Version))
1487 if (eh->SetEventID(Event, EventID))
1496 if (eh->SetTitle(Event, Title))
1505 if (eh->SetShortText(Event, ShortText))
1514 if (eh->SetDescription(Event, Description))
1523 if (eh->SetContents(Event, Contents))
1532 if (eh->SetParentalRating(Event, ParentalRating))
1541 if (eh->SetStartTime(Event, StartTime))
1550 if (eh->SetDuration(Event, Duration))
1559 if (eh->SetVps(Event, Vps))
1568 if (eh->SetComponents(Event, Components))
1577 if (eh->FixEpgBugs(Event))
1586 if (eh->HandleEvent(Event))
1594 if (eh->SortSchedule(Schedule))
1603 if (eh->DropOutdated(Schedule, SegmentStart, SegmentEnd, TableID, Version))
1606 Schedule->
DropOutdated(SegmentStart, SegmentEnd, TableID, Version);
1612 if (!eh->BeginSegmentTransfer(Channel,
false))
1621 if (eh->EndSegmentTransfer(Modified,
false))
#define LOCK_CHANNELS_READ
#define LOCK_CHANNELS_WRITE
const char * Name(void) const
tChannelID GetChannelID(void) const
const cSchedule * schedule
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
tComponent * GetComponent(int Index, uchar Stream, uchar Type)
tComponent * Component(int Index) const
int NumComponents(void) const
void SetComponent(int Index, const char *s)
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
cEpgHandler(void)
Constructs a new EPG handler and adds it to the list of EPG handlers.
void SortSchedule(cSchedule *Schedule)
void EndSegmentTransfer(bool Modified)
bool IgnoreChannel(const cChannel *Channel)
bool HandleEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version)
void SetStartTime(cEvent *Event, time_t StartTime)
void SetTitle(cEvent *Event, const char *Title)
void DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version)
bool IsUpdate(tEventID EventID, time_t StartTime, uchar TableID, uchar Version)
void FixEpgBugs(cEvent *Event)
void HandleEvent(cEvent *Event)
void SetComponents(cEvent *Event, cComponents *Components)
void SetVps(cEvent *Event, time_t Vps)
void SetParentalRating(cEvent *Event, int ParentalRating)
bool BeginSegmentTransfer(const cChannel *Channel)
bool HandledExternally(const cChannel *Channel)
void SetContents(cEvent *Event, uchar *Contents)
void SetShortText(cEvent *Event, const char *ShortText)
void SetDuration(cEvent *Event, int Duration)
void SetDescription(cEvent *Event, const char *Description)
void SetEventID(cEvent *Event, tEventID EventID)
const char * ShortText(void) const
cString ToDescr(void) const
static const char * ContentToString(uchar Content)
uchar TableID(void) const
void SetAux(const char *Aux)
time_t EndTime(void) const
static cMutex numTimersMutex
cString GetDateString(void) const
int RunningStatus(void) const
const cComponents * Components(void) const
uchar Contents(int i=0) const
const char * Description(void) const
bool IsRunning(bool OrAboutToStart=false) const
void SetRunningStatus(int RunningStatus, const cChannel *Channel=NULL)
void IncNumTimers(void) const
int ParentalRating(void) const
time_t StartTime(void) const
tChannelID ChannelID(void) const
static bool Read(FILE *f, cSchedule *Schedule, int &Line)
const char * Aux(void) const
void SetShortText(const char *ShortText)
cString GetTimeString(void) const
const char * Title(void) const
void DecNumTimers(void) const
tEventID EventID(void) const
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
const cSchedule * Schedule(void) const
void SetStartTime(time_t StartTime)
bool HasTimer(void) const
void SetComponents(cComponents *Components)
void SetEventID(tEventID EventID)
cString GetEndTimeString(void) const
cString GetVpsString(void) const
void SetVersion(uchar Version)
void Dump(FILE *f, const char *Prefix="", bool InfoOnly=false) const
void SetDuration(int Duration)
void SetContents(uchar *Contents)
uchar Version(void) const
void SetTitle(const char *Title)
void SetTableID(uchar TableID)
uchar contents[MaxEventContents]
cString GetParentalRatingString(void) const
void SetDescription(const char *Description)
void SetParentalRating(int ParentalRating)
void Del(cListObject *Object, unsigned int Id)
void Add(cListObject *Object, unsigned int Id)
T * Get(unsigned int Id) const
void Del(cListObject *Object, bool DeleteObject=true)
void SetUseGarbageCollector(void)
bool Lock(cStateKey &StateKey, bool Write=false, int TimeoutMs=0) const
Tries to get a lock on this list and returns true if successful.
void Add(cListObject *Object, cListObject *After=NULL)
cListObject * Next(void) const
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
const cEvent * GetPresentEvent(void) const
cHash< cEvent > eventsHashID
bool HasTimer(void) const
void SetRunningStatus(cEvent *Event, int RunningStatus, const cChannel *Channel=NULL)
void UnhashEvent(cEvent *Event)
const cEvent * GetEventAround(time_t Time) const
const cEvent * GetEventByTime(time_t StartTime) const
void DecNumTimers(void) const
const cEvent * GetEvent(tEventID EventID, time_t StartTime=0) const
bool OnActualTp(uchar TableId)
void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version)
static bool Read(FILE *f, cSchedules *Schedules)
cSchedule(tChannelID ChannelID)
void SetPresentSeen(void)
static cMutex numTimersMutex
void ClrRunningStatus(cChannel *Channel=NULL)
const cEvent * GetEventById(tEventID EventID) const
void DelEvent(cEvent *Event)
void HashEvent(cEvent *Event)
tChannelID ChannelID(void) const
cHash< cEvent > eventsHashStartTime
void IncNumTimers(void) const
cEvent * AddEvent(cEvent *Event)
void Dump(const cChannels *Channels, FILE *f, const char *Prefix="", eDumpMode DumpMode=dmAll, time_t AtTime=0) const
const cEvent * GetFollowingEvent(void) const
static cSchedules * GetSchedulesWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for write access.
const cSchedule * GetSchedule(tChannelID ChannelID) const
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
static bool Dump(FILE *f=NULL, const char *Prefix="", eDumpMode DumpMode=dmAll, time_t AtTime=0)
static void SetEpgDataFileName(const char *FileName)
static void Cleanup(bool Force=false)
static char * epgDataFileName
static void ResetVersions(void)
cSchedule * AddSchedule(tChannelID ChannelID)
static bool Read(FILE *f=NULL)
static cSchedules schedules
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
static cString sprintf(const char *fmt,...) __attribute__((format(printf
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
bool Active(void)
Checks whether the thread is still alive.
#define EPGDATAWRITEDELTA
static void StripControlCharacters(char *s)
tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS]
void ReportEpgBugFixStats(bool Force)
#define MAXEPGBUGFIXCHANS
#define MAX_USEFUL_EPISODE_LENGTH
#define RUNNINGSTATUSTIMEOUT
#define MAXEPGBUGFIXSTATS
static void EpgBugFixStat(int Number, tChannelID ChannelID)
static cEpgDataWriter EpgDataWriter
#define LOCK_SCHEDULES_READ
#define LOCK_SCHEDULES_WRITE
@ ecgSocialPoliticalEconomics
@ RunningStatusNotRunning
@ RunningStatusStartsInAFewSeconds
tChannelID & ClrRid(void)
static const tChannelID InvalidID
static tChannelID FromString(const char *s)
bool FromString(const char *s)
char language[MAXLANGCODE2]
tChannelID channelIDs[MAXEPGBUGFIXCHANS]