summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorschmirl <schmirl>2008-03-28 15:13:11 +0000
committerschmirl <schmirl>2008-03-28 15:13:11 +0000
commit57923c656e264a032391693132fbe3add86df941 (patch)
tree8224248c89071f96cb6a0ad0a43854dcf1cea8ad
parentb66bf7a698738389a030d1512d5442c149ab27db (diff)
downloadvdr-plugin-streamdev-57923c656e264a032391693132fbe3add86df941.tar.gz
vdr-plugin-streamdev-57923c656e264a032391693132fbe3add86df941.tar.bz2
Missing files
-rw-r--r--server/menuHTTP.c420
-rw-r--r--server/menuHTTP.h140
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