diff options
author | schmirl <schmirl> | 2008-03-28 15:13:11 +0000 |
---|---|---|
committer | schmirl <schmirl> | 2008-03-28 15:13:11 +0000 |
commit | 57923c656e264a032391693132fbe3add86df941 (patch) | |
tree | 8224248c89071f96cb6a0ad0a43854dcf1cea8ad /server | |
parent | b66bf7a698738389a030d1512d5442c149ab27db (diff) | |
download | vdr-plugin-streamdev-57923c656e264a032391693132fbe3add86df941.tar.gz vdr-plugin-streamdev-57923c656e264a032391693132fbe3add86df941.tar.bz2 |
Missing files
Diffstat (limited to 'server')
-rw-r--r-- | server/menuHTTP.c | 420 | ||||
-rw-r--r-- | server/menuHTTP.h | 140 |
2 files changed, 560 insertions, 0 deletions
diff --git a/server/menuHTTP.c b/server/menuHTTP.c new file mode 100644 index 0000000..b5bb299 --- /dev/null +++ b/server/menuHTTP.c @@ -0,0 +1,420 @@ +#include <vdr/channels.h> +#include "server/menuHTTP.h" + +//**************************** cChannelIterator ************** +cChannelIterator::cChannelIterator(cChannel *First): channel(First) +{} + +const cChannel* cChannelIterator::Next() +{ + const cChannel *current = channel; + channel = NextChannel(channel); + return current; +} + +//**************************** cListAll ************** +cListAll::cListAll(): cChannelIterator(Channels.First()) +{} + +const cChannel* cListAll::NextChannel(const cChannel *Channel) +{ + if (Channel) + Channel = Channels.Next(Channel); + return Channel; +} + +//**************************** cListChannels ************** +cListChannels::cListChannels(): cChannelIterator(Channels.Get(Channels.GetNextNormal(-1))) +{} + +const cChannel* cListChannels::NextChannel(const cChannel *Channel) +{ + if (Channel) + Channel = Channels.Get(Channels.GetNextNormal(Channel->Index())); + return Channel; +} + +// ********************* cListGroups **************** +cListGroups::cListGroups(): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1))) +{} + +const cChannel* cListGroups::NextChannel(const cChannel *Channel) +{ + if (Channel) + Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); + return Channel; +} +// +// ********************* cListGroup **************** +cListGroup::cListGroup(const cChannel *Group): cChannelIterator((Group && Group->GroupSep() && Channels.Next(Group) && !Channels.Next(Group)->GroupSep()) ? Channels.Next(Group) : NULL) +{} + +const cChannel* cListGroup::NextChannel(const cChannel *Channel) +{ + if (Channel) + Channel = Channels.Next(Channel); + return (Channel && !Channel->GroupSep()) ? Channel : NULL; +} +// +// ********************* cListTree **************** +cListTree::cListTree(const cChannel *SelectedGroup): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1))) +{ + selectedGroup = SelectedGroup; + currentGroup = Channels.Get(Channels.GetNextGroup(-1)); +} + +const cChannel* cListTree::NextChannel(const cChannel *Channel) +{ + if (currentGroup == selectedGroup) + { + if (Channel) + Channel = Channels.Next(Channel); + if (Channel && Channel->GroupSep()) + currentGroup = Channel; + } + else + { + if (Channel) + Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); + currentGroup = Channel; + } + return Channel; +} + +// ******************** cChannelList ****************** +cChannelList::cChannelList(cChannelIterator *Iterator) : iterator(Iterator) +{} + +cChannelList::~cChannelList() +{ + delete iterator; +} + +int cChannelList::GetGroupIndex(const cChannel *Group) +{ + int index = 0; + for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr)) + { + if (Channels.Get(curr) == Group) + return index; + index++; + } + return -1; +} + +const cChannel* cChannelList::GetGroup(int Index) +{ + int group = Channels.GetNextGroup(-1); + while (Index-- && group >= 0) + group = Channels.GetNextGroup(group); + return group >= 0 ? Channels.Get(group) : NULL; +} + +// ******************** cHtmlChannelList ****************** +const char* cHtmlChannelList::menu = + "[<a href=\"/\">Home</a> (<a href=\"all.html\">no script</a>)] " + "[<a href=\"tree.html\">Tree View</a>] " + "[<a href=\"groups.html\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] " + "[<a href=\"channels.html\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] "; + +const char* cHtmlChannelList::css = + "<style type=\"text/css\">\n" + "<!--\n" + "a:link, a:visited, a:hover, a:active, a:focus { color:#333399; }\n" + "body { font:100% Verdana, Arial, Helvetica, sans-serif; background-color:#9999FF; margin:1em; }\n" + ".menu { position:fixed; top:0px; left:1em; right:1em; height:3em; text-align:center; background-color:white; border:inset 2px #9999ff; }\n" + "h2 { font-size:150%; margin:0em; padding:0em 1.5em; }\n" + ".contents { margin-top:5em; background-color:white; }\n" + ".group { background:url(data:image/gif;base64,R0lGODdhAQAeAIQeAJub/5yc/6Cf/6Oj/6am/6qq/66u/7Gx/7S0/7i4/7u8/7+//8LD/8bG/8nK/83N/9HQ/9TU/9fX/9va/97e/+Lh/+Xl/+no/+3t//Dw//Pz//b3//v7//7+/////////ywAAAAAAQAeAAAFGCAQCANRGAeSKAvTOA8USRNVWReWaRvXhQA7) repeat-x; border:inset 2px #9999ff; }\n" + ".items { border-top:dashed 1px; margin-top:0px; margin-bottom:0px; padding:0.7em 5em; }\n" + ".apid { padding-left:28px; margin:0.5em; background:url(data:image/gif;base64,R0lGODlhGwASAKEBAAAAAP///////////yH5BAEKAAEALAAAAAAbABIAAAJAjI+pywj5WgPxVAmpNRcHqnGb94FPhE7m+okts7JvusSmSys2iLv6TstldjMfhhUkcXi+zjFUVFo6TiVVij0UAAA7) no-repeat; }\n" + ".dpid { padding-left:28px; margin:0.5em; background:url(data:image/gif;base64,R0lGODlhGwASAKEBAAAAAP///////////yH5BAEKAAEALAAAAAAbABIAAAJFjI+py+0BopwAUoqivRvr83UaZ4RWMnVoBbLZaJbuqcCLGcv0+t5Vvgu2hLrh6pfDzVSpnlGEbAZhnIutZaVmH9yuV1EAADs=) no-repeat; }\n" + "button { width:2em; margin:0.2em 0.5em; vertical-align:top; }\n" + "-->\n" + "</style>"; + +const char* cHtmlChannelList::js = + "<script language=\"JavaScript\">\n" + "<!--\n" + + "function eventTarget(evt) {\n" + " if (!evt) evt = window.event;\n" + " if (evt.target) return evt.target;\n" + " else if (evt.srcElement) return evt.srcElement;\n" + " else return null;\n" + "}\n" + + // toggle visibility of a group + "function clickHandler(evt) {\n" + " var button = eventTarget(evt);\n" + " if (button) {\n" + " var group = document.getElementById('c' + button.id);\n" + " if (group) {\n" + " button.removeChild(button.firstChild);\n" + " if (group.style.display == 'block') {\n" + " button.appendChild(document.createTextNode(\"+\"));\n" + " group.style.display = 'none';\n" + " } else {\n" + " button.appendChild(document.createTextNode(\"-\"));\n" + " group.style.display = 'block';\n" + " }\n" + " }\n" + " }\n" + "}\n" + + // insert a click button infront of each h2 and an id to the corresponding list + "function init() {\n" + " var titles = document.getElementsByTagName('h2');\n" + " for (var i = 0; i < titles.length; i++) {\n" + " var button = document.createElement('button');\n" + " button.id = 'g' + i;\n" + " button.onclick = clickHandler;\n" + " button.appendChild(document.createTextNode('+'));\n" + " titles[i].insertBefore(button, titles[i].firstChild);\n" + " var group = titles[i].nextSibling;\n" + " while (group) {\n" + " if (group.className && group.className == 'items') {\n" + " group.id = 'cg' + i;\n" + " break;\n" + " }\n" + " group = group.nextSibling;\n" + " }\n" + " }\n" + "}\n" + + "window.onload = init;\n" + + // hide lists before the browser renders it + "if (document.styleSheets[0].insertRule)\n" + " document.styleSheets[0].insertRule('.items { display:none }', 0);\n" + "else if (document.styleSheets[0].addRule)\n" + " document.styleSheets[0].addRule('.items', 'display:none');\n" + + "//-->\n" + "</script>"; + + +std::string cHtmlChannelList::StreamTypeMenu() +{ + std::string typeMenu; + typeMenu += (streamType == stTS ? (std::string) "[TS] " : + (std::string) "[<a href=\"/TS/" + self + "\">TS</a>] "); + typeMenu += (streamType == stPS ? (std::string) "[PS] " : + (std::string) "[<a href=\"/PS/" + self + "\">PS</a>] "); + typeMenu += (streamType == stPES ? (std::string) "[PES] " : + (std::string) "[<a href=\"/PES/" + self + "\">PES</a>] "); + typeMenu += (streamType == stES ? (std::string) "[ES] " : + (std::string) "[<a href=\"/ES/" + self + "\">ES</a>] "); + typeMenu += (streamType == stExtern ? (std::string) "[Extern] " : + (std::string) "[<a href=\"/Extern/" + self + "\">Extern</a>] "); + return typeMenu; +} + +cHtmlChannelList::cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget): cChannelList(Iterator) +{ + streamType = StreamType; + self = strdup(Self); + groupTarget = (GroupTarget && *GroupTarget) ? strdup(GroupTarget) : NULL; + htmlState = hsRoot; + current = NULL; +} + +cHtmlChannelList::~cHtmlChannelList() +{ + free((void *) self); + free((void *) groupTarget); +} + +bool cHtmlChannelList::HasNext() +{ + return htmlState != hsPageBottom; +} + +std::string cHtmlChannelList::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: + current = NextChannel(); + htmlState = current ? (current->GroupSep() ? hsGroupTop : hsPlainTop) : hsPageBottom; + break; + case hsPlainTop: + htmlState = hsPlainItem; + break; + case hsPlainItem: + current = NextChannel(); + htmlState = current && !current->GroupSep() ? hsPlainItem : hsPlainBottom; + break; + case hsPlainBottom: + htmlState = current ? hsGroupTop : hsPageBottom; + break; + case hsGroupTop: + current = NextChannel(); + htmlState = current && !current->GroupSep() ? hsItemsTop : hsGroupBottom; + break; + case hsItemsTop: + htmlState = hsItem; + break; + case hsItem: + current = NextChannel(); + htmlState = current && !current->GroupSep() ? hsItem : hsItemsBottom; + break; + case hsItemsBottom: + htmlState = hsGroupBottom; + break; + case hsGroupBottom: + htmlState = current ? hsGroupTop : hsPageBottom; + break; + case hsPageBottom: + default: + esyslog("streamdev-server cHtmlChannelList: invalid call to Next()"); + break; + } + switch (htmlState) + { + // NOTE: JavaScript requirements: + // Group title is identified by <h2> tag + // Channel list must be a sibling of <h2> with class "items" + case hsHtmlHead: return "<html><head>" + HtmlHead(); + case hsCss: return css; + case hsJs: return js; + case hsPageTop: return "</head><body>" + PageTop() + "<div class=\"contents\">"; + case hsGroupTop: return "<div class=\"group\"><h2>" + GroupTitle() + "</h2>"; + case hsItemsTop: + case hsPlainTop: return "<ol class=\"items\">"; + case hsItem: + case hsPlainItem: return ItemText(); + case hsItemsBottom: + case hsPlainBottom: return "</ol>"; + case hsGroupBottom: return "</div>"; + case hsPageBottom: return "</div>" + PageBottom() + "</body></html>"; + default: return ""; + } +} + +std::string cHtmlChannelList::HtmlHead() +{ + return (std::string) ""; +} + +std::string cHtmlChannelList::PageTop() +{ + return (std::string) "<div class=\"menu\"><div>" + menu + "</div><div>" + StreamTypeMenu() + "</div></div>"; +} + +std::string cHtmlChannelList::PageBottom() +{ + return (std::string) ""; +} + +std::string cHtmlChannelList::GroupTitle() +{ + if (groupTarget) + { + return (std::string) "<a href=\"" + groupTarget + "?group=" + + (const char*) itoa(cChannelList::GetGroupIndex(current)) + + "\">" + current->Name() + "</a>"; + } + else + { + return (std::string) current->Name(); + } +} + +std::string cHtmlChannelList::ItemText() +{ + std::string line; + line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">"; + line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + "\">" + + current->Name() + "</a>"; + + int count = 0; + for (int i = 0; current->Apid(i) != 0; ++i, ++count) + ; + for (int i = 0; current->Dpid(i) != 0; ++i, ++count) + ; + + if (count > 1) + { + int index = 1; + for (int i = 0; current->Apid(i) != 0; ++i, ++index) { + line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() + + "+" + (const char*)itoa(index) + "\" class=\"apid\">" + current->Alang(i) + "</a>"; + } + for (int i = 0; current->Dpid(i) != 0; ++i, ++index) { + line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() + + "+" + (const char*)itoa(index) + "\" class=\"dpid\">" + current->Dlang(i) + "</a>"; + } + } + line += "</li>"; + return line; +} + +// ******************** cM3uChannelList ****************** +cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base) +: cChannelList(Iterator) +#if defined(APIVERSNUM) && APIVERSNUM >= 10503 + , m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8") +#endif +{ + base = strdup(Base); + m3uState = msFirst; +} + +cM3uChannelList::~cM3uChannelList() +{ + free(base); +} + +bool cM3uChannelList::HasNext() +{ + return m3uState != msLast; +} + +std::string cM3uChannelList::Next() +{ + if (m3uState == msFirst) + { + m3uState = msContinue; + return "#EXTM3U"; + } + + const cChannel *channel = NextChannel(); + if (!channel) + { + m3uState = msLast; + return ""; + } + +#if defined(APIVERSNUM) && APIVERSNUM >= 10503 + std::string name = (std::string) m_IConv.Convert(channel->Name()); +#else + std::string name = channel->Name(); +#endif + + if (channel->GroupSep()) + { + return (std::string) "#EXTINF:0," + name + "\r\n" + + base + "group.m3u?group=" + + (const char*) itoa(cChannelList::GetGroupIndex(channel)); + } + else + { + return (std::string) "#EXTINF:0," + + (const char*) itoa(channel->Number()) + " " + name + "\r\n" + + base + (std::string) channel->GetChannelID().ToString(); + } +} + diff --git a/server/menuHTTP.h b/server/menuHTTP.h new file mode 100644 index 0000000..8be613b --- /dev/null +++ b/server/menuHTTP.h @@ -0,0 +1,140 @@ +#ifndef VDR_STREAMDEV_SERVERS_MENUHTTP_H +#define VDR_STREAMDEV_SERVERS_MENUHTTP_H + +#include <string> +#include "../common.h" + +class cChannel; + +// ******************** cChannelIterator ****************** +class cChannelIterator +{ + private: + const cChannel *channel; + protected: + virtual const cChannel* NextChannel(const cChannel *Channel) = 0; + public: + const cChannel* Next(); + cChannelIterator(cChannel *First); + virtual ~cChannelIterator() {}; +}; + +class cListAll: public cChannelIterator +{ + protected: + virtual const cChannel* NextChannel(const cChannel *Channel); + public: + cListAll(); + virtual ~cListAll() {}; +}; + +class cListChannels: public cChannelIterator +{ + protected: + virtual const cChannel* NextChannel(const cChannel *Channel); + public: + cListChannels(); + virtual ~cListChannels() {}; +}; + +class cListGroups: public cChannelIterator +{ + protected: + virtual const cChannel* NextChannel(const cChannel *Channel); + public: + cListGroups(); + virtual ~cListGroups() {}; +}; + +class cListGroup: public cChannelIterator +{ + protected: + virtual const cChannel* NextChannel(const cChannel *Channel); + public: + cListGroup(const cChannel *Group); + virtual ~cListGroup() {}; +}; + +class cListTree: public cChannelIterator +{ + private: + const cChannel* selectedGroup; + const cChannel* currentGroup; + protected: + virtual const cChannel* NextChannel(const cChannel *Channel); + public: + cListTree(const cChannel *SelectedGroup); + virtual ~cListTree() {}; +}; + +// ******************** cChannelList ****************** +class cChannelList +{ + private: + cChannelIterator *iterator; + protected: + const cChannel* NextChannel() { return iterator->Next(); } + public: + // Helper which returns the group index + static int GetGroupIndex(const cChannel* Group); + // Helper which returns the group by its index + static const cChannel* GetGroup(int Index); + + virtual std::string HttpHeader() { return "HTTP/1.0 200 OK\r\n"; }; + virtual bool HasNext() = 0; + virtual std::string Next() = 0; + cChannelList(cChannelIterator *Iterator); + virtual ~cChannelList(); +}; + +class cHtmlChannelList: public cChannelList +{ + private: + static const char* menu; + static const char* css; + static const char* js; + + enum eHtmlState { + hsRoot, hsHtmlHead, hsCss, hsJs, hsPageTop, hsPageBottom, + hsGroupTop, hsGroupBottom, + hsPlainTop, hsPlainItem, hsPlainBottom, + hsItemsTop, hsItem, hsItemsBottom + }; + eHtmlState htmlState; + const cChannel *current; + eStreamType streamType; + const char* self; + const char* groupTarget; + + std::string StreamTypeMenu(); + std::string HtmlHead(); + std::string PageTop(); + std::string GroupTitle(); + std::string ItemText(); + std::string PageBottom(); + public: + virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: text/html\r\n\r\n"; } + virtual bool HasNext(); + virtual std::string Next(); + cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget); + virtual ~cHtmlChannelList(); +}; + +class cM3uChannelList: public cChannelList +{ + private: + char *base; + enum eM3uState { msFirst, msContinue, msLast }; + eM3uState m3uState; +#if defined(APIVERSNUM) && APIVERSNUM >= 10503 + cCharSetConv m_IConv; +#endif + public: + virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl\r\n"; }; + virtual bool HasNext(); + virtual std::string Next(); + cM3uChannelList(cChannelIterator *Iterator, const char* Base); + virtual ~cM3uChannelList(); +}; + +#endif |