#include #include #include #include #include "server/menuHTTP.h" //**************************** cRecordingIterator ************** #if APIVERSNUM >= 20300 cRecordingsIterator::cRecordingsIterator(eStreamType StreamType) #else cRecordingsIterator::cRecordingsIterator(eStreamType StreamType): RecordingsLock(&Recordings) #endif { streamType = StreamType; #if APIVERSNUM >= 20300 LOCK_RECORDINGS_READ; first = NextSuitable(Recordings->First()); #else first = NextSuitable(Recordings.First()); #endif current = NULL; } const cRecording* cRecordingsIterator::NextSuitable(const cRecording *Recording) { while (Recording) { bool isPes = Recording->IsPesRecording(); if (!isPes || (isPes && streamType == stPES)) break; #if APIVERSNUM >= 20300 LOCK_RECORDINGS_READ; Recording = Recordings->Next(Recording); #else Recording = Recordings.Next(Recording); #endif } return Recording; } bool cRecordingsIterator::Next() { #if APIVERSNUM >= 20300 LOCK_RECORDINGS_READ; #endif if (first) { current = first; first = NULL; } else #if APIVERSNUM >= 20300 current = NextSuitable(Recordings->Next(current)); #else current = NextSuitable(Recordings.Next(current)); #endif return current; } const cString cRecordingsIterator::ItemRessource() const { struct stat st; if (stat(current->FileName(), &st) == 0) return cString::sprintf("%lu:%llu.rec", (unsigned long) st.st_dev, (unsigned long long) st.st_ino); return ""; } //**************************** cChannelIterator ************** cChannelIterator::cChannelIterator(const cChannel *First) { first = First; current = NULL; } bool cChannelIterator::Next() { if (first) { current = first; first = NULL; } else current = NextChannel(current); return current; } const cString cChannelIterator::ItemId() const { if (current) { if (current->GroupSep()) { int index = 0; #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; for (int curr = Channels->GetNextGroup(-1); curr >= 0; curr = Channels->GetNextGroup(curr)) { if (Channels->Get(curr) == current) #else for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr)) { if (Channels.Get(curr) == current) #endif return itoa(index); index++; } } else { return itoa(current->Number()); } } return cString("-1"); } const cChannel* cChannelIterator::GetGroup(const char* GroupId) { int group = -1; #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; #endif if (GroupId) { int Index = atoi(GroupId); #if APIVERSNUM >= 20300 group = Channels->GetNextGroup(-1); while (Index-- && group >= 0) group = Channels->GetNextGroup(group); } return group >= 0 ? Channels->Get(group) : NULL; #else group = Channels.GetNextGroup(-1); while (Index-- && group >= 0) group = Channels.GetNextGroup(group); } return group >= 0 ? Channels.Get(group) : NULL; #endif } const cChannel* cChannelIterator::FirstChannel() { const cChannel *Channel; #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; Channel = Channels->First(); #else Channel = Channels.First(); #endif return Channel; } const cChannel* cChannelIterator::NextNormal() { const cChannel *Channel; #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; Channel = Channels->Get(Channels->GetNextNormal(-1)); #else Channel = Channels.Get(Channels.GetNextNormal(-1)); #endif return Channel; } const cChannel* cChannelIterator::NextGroup() { const cChannel *Channel; #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; Channel = Channels->Get(Channels->GetNextGroup(-1)); #else Channel = Channels.Get(Channels.GetNextGroup(-1)); #endif return Channel; } //**************************** cListAll ************** cListAll::cListAll(): cChannelIterator(FirstChannel()) {} const cChannel* cListAll::NextChannel(const cChannel *Channel) { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = SkipFakeGroups(Channels->Next(Channel)); #else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); #endif return Channel; } //**************************** cListChannels ************** cListChannels::cListChannels(): cChannelIterator(NextNormal()) {} const cChannel* cListChannels::NextChannel(const cChannel *Channel) { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = Channels->Get(Channels->GetNextNormal(Channel->Index())); #else if (Channel) Channel = Channels.Get(Channels.GetNextNormal(Channel->Index())); #endif return Channel; } // ********************* cListGroups **************** cListGroups::cListGroups(): cChannelIterator(NextGroup()) {} const cChannel* cListGroups::NextChannel(const cChannel *Channel) { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = Channels->Get(Channels->GetNextGroup(Channel->Index())); #else if (Channel) Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); #endif return Channel; } // // ********************* cListGroup **************** cListGroup::cListGroup(const char *GroupId): cChannelIterator(GetNextChannelInGroup(GetGroup(GroupId))) {} const cChannel* cListGroup::GetNextChannelInGroup(const cChannel *Channel) { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = SkipFakeGroups(Channels->Next(Channel)); #else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); #endif return Channel && !Channel->GroupSep() ? Channel : NULL; } const cChannel* cListGroup::NextChannel(const cChannel *Channel) { return GetNextChannelInGroup(Channel); } // // ********************* cListTree **************** cListTree::cListTree(const char *SelectedGroupId): cChannelIterator(NextGroup()) { selectedGroup = GetGroup(SelectedGroupId); #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; currentGroup = Channels->Get(Channels->GetNextGroup(-1)); #else currentGroup = Channels.Get(Channels.GetNextGroup(-1)); #endif } const cChannel* cListTree::NextChannel(const cChannel *Channel) { if (currentGroup == selectedGroup) { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = SkipFakeGroups(Channels->Next(Channel)); #else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); #endif if (Channel && Channel->GroupSep()) currentGroup = Channel; } else { #if APIVERSNUM >= 20300 LOCK_CHANNELS_READ; if (Channel) Channel = Channels->Get(Channels->GetNextGroup(Channel->Index())); #else if (Channel) Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); #endif currentGroup = Channel; } return Channel; } // ******************** cMenuList ****************** cMenuList::cMenuList(cItemIterator *Iterator) : iterator(Iterator) {} cMenuList::~cMenuList() { delete iterator; } // ******************** cHtmlMenuList ****************** const char* cHtmlMenuList::menu = "[Home (no script)] " "[Tree View] " "[Groups (Playlist | RSS)] " "[Channels (Playlist | RSS)] " "[Recordings (Playlist | RSS)] "; const char* cHtmlMenuList::css = ""; const char* cHtmlMenuList::js = ""; std::string cHtmlMenuList::StreamTypeMenu() { std::string typeMenu; typeMenu += (streamType == stTS ? (std::string) "[TS] " : (std::string) "[TS] "); #ifdef STREAMDEV_PS typeMenu += (streamType == stPS ? (std::string) "[PS] " : (std::string) "[PS] "); #endif typeMenu += (streamType == stPES ? (std::string) "[PES] " : (std::string) "[PES] "); typeMenu += (streamType == stES ? (std::string) "[ES] " : (std::string) "[ES] "); typeMenu += (streamType == stEXT ? (std::string) "[EXT] " : (std::string) "[EXT] "); return typeMenu; } cHtmlMenuList::cHtmlMenuList(cItemIterator *Iterator, eStreamType StreamType, const char *Self, const char *Rss, const char *GroupTarget): cMenuList(Iterator) { streamType = StreamType; self = strdup(Self); rss = strdup(Rss); groupTarget = (GroupTarget && *GroupTarget) ? strdup(GroupTarget) : NULL; htmlState = hsRoot; onItem = true; } cHtmlMenuList::~cHtmlMenuList() { free((void *) self); free((void *) rss); free((void *) groupTarget); } bool cHtmlMenuList::HasNext() { return htmlState != hsPageBottom; } std::string cHtmlMenuList::Next() { switch (htmlState) { case hsRoot: htmlState = hsHtmlHead; break; case hsHtmlHead: htmlState = hsCss; break; case hsCss: htmlState = *self ? hsPageTop : hsJs; break; case hsJs: htmlState = hsPageTop; break; case hsPageTop: onItem = NextItem(); htmlState = onItem ? (IsGroup() ? hsGroupTop : hsPlainTop) : hsPageBottom; break; case hsPlainTop: htmlState = hsPlainItem; break; case hsPlainItem: onItem = NextItem(); htmlState = onItem && !IsGroup() ? hsPlainItem : hsPlainBottom; break; case hsPlainBottom: htmlState = onItem ? hsGroupTop : hsPageBottom; break; case hsGroupTop: onItem = NextItem(); htmlState = onItem && !IsGroup() ? hsItemsTop : hsGroupBottom; break; case hsItemsTop: htmlState = hsItem; break; case hsItem: onItem = NextItem(); htmlState = onItem && !IsGroup() ? hsItem : hsItemsBottom; break; case hsItemsBottom: htmlState = hsGroupBottom; break; case hsGroupBottom: htmlState = onItem ? hsGroupTop : hsPageBottom; break; case hsPageBottom: default: esyslog("streamdev-server cHtmlMenuList: invalid call to Next()"); break; } switch (htmlState) { // NOTE: JavaScript requirements: // Group title is identified by

tag // Channel list must be a sibling of

with class "items" case hsHtmlHead: return "" + HtmlHead(); case hsCss: return css; case hsJs: return js; case hsPageTop: return "" + PageTop() + "
"; case hsGroupTop: return "

" + GroupTitle() + "

"; case hsItemsTop: case hsPlainTop: return "
    "; case hsItem: case hsPlainItem: return ItemText(); case hsItemsBottom: case hsPlainBottom: return "
"; case hsGroupBottom: return "
"; case hsPageBottom: return "
" + PageBottom() + ""; default: return ""; } } std::string cHtmlMenuList::HtmlHead() { return (std::string) ""; } std::string cHtmlMenuList::PageTop() { return (std::string) "
" + menu + "
" + StreamTypeMenu() + "
"; } std::string cHtmlMenuList::PageBottom() { return (std::string) ""; } std::string cHtmlMenuList::GroupTitle() { if (groupTarget) { return (std::string) "" + ItemTitle() + ""; } else { return (std::string) ItemTitle(); } } std::string cHtmlMenuList::ItemText() { std::string line; std::string suffix; switch (streamType) { case stTS: suffix = (std::string) ".ts"; break; #ifdef STREAMDEV_PS case stPS: suffix = (std::string) ".vob"; break; #endif // for Network Media Tank case stPES: suffix = (std::string) ".vdr"; break; default: suffix = ""; } line += (std::string) "
  • "; line += (std::string) "" + ItemTitle() + ""; // TS always streams all PIDs if (streamType != stTS) { int index = 1; const char* lang; std::string pids; for (int i = 0; (lang = Alang(i)) != NULL; ++i, ++index) { pids += (std::string) " " + (const char*) lang + ""; } for (int i = 0; (lang = Dlang(i)) != NULL; ++i, ++index) { pids += (std::string) " " + (const char*) lang + ""; } // always show audio PIDs for stES to select audio only if (index > 2 || streamType == stES) line += pids; } line += "
  • "; return line; } // ******************** cM3uMenuList ****************** cM3uMenuList::cM3uMenuList(cItemIterator *Iterator, const char* Base) : cMenuList(Iterator), m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8") { base = strdup(Base); m3uState = msFirst; } cM3uMenuList::~cM3uMenuList() { free(base); } bool cM3uMenuList::HasNext() { return m3uState != msLast; } std::string cM3uMenuList::Next() { if (m3uState == msFirst) { m3uState = msContinue; return "#EXTM3U"; } if (!NextItem()) { m3uState = msLast; return ""; } std::string name = (std::string) m_IConv.Convert(ItemTitle()); if (IsGroup()) { return (std::string) "#EXTINF:-1," + name + "\r\n" + base + "group.m3u?group=" + (const char*) ItemId(); } else { return (std::string) "#EXTINF:-1," + (const char*) ItemId() + " " + name + "\r\n" + base + (const char*) ItemRessource(); } } // ******************** cRssMenuList ****************** cRssMenuList::cRssMenuList(cItemIterator *Iterator, const char *Base, const char *Html) : cMenuList(Iterator), m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8") { base = strdup(Base); html = strdup(Html); rssState = msFirst; } cRssMenuList::~cRssMenuList() { free(base); free(html); } bool cRssMenuList::HasNext() { return rssState != msLast; } std::string cRssMenuList::Next() { std::string type_ext; if (rssState == msFirst) { rssState = msContinue; return (std::string) "\n\n\t\n" "\t\tVDR\n" "\t\t" + base + html + "\n" "\t\tVDR channel list\n" ; } if (!NextItem()) { rssState = msLast; return "\t\n\n"; } std::string name = (std::string) m_IConv.Convert(ItemTitle()); if (IsGroup()) { return (std::string) "\t\t\n\t\t\t" + name + "\n\t\t\t" + base + "group.rss?group=" + (const char*) ItemId() + "\n\t\t\n"; } else { return (std::string) "\t\t\n\t\t\t" + (const char*) ItemId() + " " + name + "\n\t\t\t" + base + (const char*) ItemRessource() + "\n\t\t\t\n\t\t\n"; } }