diff options
author | Christian <zerov83@gmail.com> | 2016-03-08 22:14:49 +0100 |
---|---|---|
committer | Christian <zerov83@gmail.com> | 2016-03-08 22:14:49 +0100 |
commit | e63b1337cb98ddfa136de78628f5048b682276ff (patch) | |
tree | f164267d8b4171a21a8a264cc41226e53f4ef056 | |
parent | 662171f45281deacdf2db255909be11ec869122c (diff) | |
download | vdr-plugin-plex-e63b1337cb98ddfa136de78628f5048b682276ff.tar.gz vdr-plugin-plex-e63b1337cb98ddfa136de78628f5048b682276ff.tar.bz2 |
Skindesigner "DetailView" in development
-rw-r--r-- | Config.cpp | 2 | ||||
-rw-r--r-- | Config.h | 3 | ||||
-rw-r--r-- | Directory.cpp | 4 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | MediaContainer.cpp | 2 | ||||
-rw-r--r-- | MediaContainer.h | 3 | ||||
-rw-r--r-- | PVideo.cpp | 30 | ||||
-rw-r--r-- | PVideo.h | 3 | ||||
-rw-r--r-- | Stream.cpp | 6 | ||||
-rw-r--r-- | XmlObject.cpp | 64 | ||||
-rw-r--r-- | XmlObject.h | 8 | ||||
-rw-r--r-- | browserGrid.cpp | 7 | ||||
-rw-r--r-- | detailView.cpp | 166 | ||||
-rw-r--r-- | detailView.h | 30 | ||||
-rw-r--r-- | hlsPlayer.cpp | 4 | ||||
-rw-r--r-- | hlsPlayerControl.cpp | 6 | ||||
-rw-r--r-- | plex.cpp | 27 | ||||
-rw-r--r-- | plexSdOsd.cpp | 188 | ||||
-rw-r--r-- | plexSdOsd.h | 9 | ||||
-rw-r--r-- | templates/plug-plex-root.xml | 2 | ||||
-rw-r--r-- | tokendefinitions.h | 27 | ||||
-rw-r--r-- | viewGridNavigator.h | 1 |
22 files changed, 506 insertions, 89 deletions
@@ -17,6 +17,8 @@ Config::Config() { ListGridRows = 12; DetailGridColumns = 1; DetailGridRows = 4; + ExtrasGridColumns = 4; + ExtrasGridRows = 1; UseMpv = false; UseAc3 = true; @@ -57,6 +57,9 @@ public: int DetailGridColumns; int DetailGridRows; + + int ExtrasGridColumns; + int ExtrasGridRows; ViewMode DefaultViewMode; diff --git a/Directory.cpp b/Directory.cpp index 100b830..d4cbb09 100644 --- a/Directory.cpp +++ b/Directory.cpp @@ -65,7 +65,7 @@ std::string Directory::GetTitle() seriesTitle = m_pParent->m_sParentTitle; switch(m_eType) { - case SEASON: + case MediaType::SEASON: return Poco::format(tr("%s - Season %d"), seriesTitle, m_iIndex); default: return m_sTitle; @@ -78,7 +78,7 @@ void Directory::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bo if(clear) grid->ClearTokens(); grid->AddIntToken((int)(eTokenGridInt::viewmode), Config::GetInstance().DefaultViewMode); grid->AddStringToken((int)(eTokenGridStr::title), m_sTitle.c_str()); - grid->AddIntToken((int)(eTokenGridInt::viewgroup), m_pParent->m_eViewGroup); + grid->AddIntToken((int)(eTokenGridInt::viewgroup), (int)m_pParent->m_eViewGroup); // Thumb, Cover, Episodepicture bool cached = false; @@ -94,7 +94,8 @@ OBJS = $(PLUGIN).o \ Stream.o \ Media.o \ plexOsd.o \ - device.o + device.o \ + playlist.o ifneq ($(DISABLESKINDESIGNER),1) OBJS += plexSdOsd.o \ diff --git a/MediaContainer.cpp b/MediaContainer.cpp index 4ad2a52..c7d4e5c 100644 --- a/MediaContainer.cpp +++ b/MediaContainer.cpp @@ -50,6 +50,8 @@ MediaContainer::MediaContainer(std::istream* response, PlexServer* Server) m_vVideos.push_back(Video(pNode, m_pServer, this)); } else if(Poco::icompare(pNode->nodeName(), "Device") == 0) { m_vDevices.push_back(Device(pNode, this)); + } else if(Poco::icompare(pNode->nodeName(), "Playlist") == 0) { + m_vPlaylists.push_back(Playlist(pNode, this)); } pNode = it.nextNode(); diff --git a/MediaContainer.h b/MediaContainer.h index 978311c..0f385be 100644 --- a/MediaContainer.h +++ b/MediaContainer.h @@ -20,6 +20,7 @@ #include "PlexServer.h" #include "Config.h" #include "device.h" +#include "playlist.h" using Poco::XML::DOMParser; using Poco::XML::InputSource; @@ -35,6 +36,7 @@ namespace plexclient class Video; class Directory; class Device; +class Playlist; class MediaContainer: XmlObject { @@ -49,6 +51,7 @@ public: std::vector<Directory> m_vDirectories; std::vector<Video> m_vVideos; std::vector<Device> m_vDevices; + std::vector<Playlist> m_vPlaylists; bool m_bAllowSync; std::string m_sArt; @@ -20,7 +20,7 @@ Video::Video(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent) Parse(pNode); m_pParent = parent; - if (m_iParentIndex < 0) { + if (m_iParentIndex < 0 && m_pParent) { m_iParentIndex = parent->m_iParentIndex; } } @@ -28,7 +28,7 @@ Video::Video(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent) bool Video::UpdateFromServer() { try { - Poco::URI fileuri(Poco::format("%s/library/metadata/%d", m_pServer->GetUri(), m_iRatingKey)); + Poco::URI fileuri(Poco::format("%s/library/metadata/%d?includeExtras=1", m_pServer->GetUri(), m_iRatingKey)); Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); PlexHelper::AddHttpHeader(request); @@ -101,6 +101,7 @@ void Video::Parse(Poco::XML::Node* pNode) m_tAddedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("addedAt")); m_tUpdatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("updatedAt")); m_tOriginallyAvailableAt = GetNodeValueAsDateTime(pAttribs->getNamedItem("originallyAvailableAt")); + m_eExtraType = GetNodeValueAsExtraType(pAttribs->getNamedItem("extraType")); pAttribs->release(); @@ -135,11 +136,26 @@ void Video::Parse(Poco::XML::Node* pNode) Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); m_sCollection = GetNodeValue(pAttribs->getNamedItem("tag")); pAttribs->release(); + } else if(Poco::icompare(pChildNode->nodeName(), "Extras") == 0) { + ParseExtras(pChildNode); } pChildNode = it.nextNode(); } } +void Video::ParseExtras(Poco::XML::Node* pNode) +{ + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node* pChildNode = it.nextNode(); + + while(pChildNode) { + if(Poco::icompare(pChildNode->nodeName(), "Video") == 0) { + m_vExtras.push_back(Video(pChildNode, m_pServer, NULL)); + } + pChildNode = it.nextNode(); + } +} + std::string Video::GetTitle() { std::string res = m_sTitle; @@ -149,14 +165,14 @@ std::string Video::GetTitle() seriesTitle = m_pParent->m_sGrandparentTitle; switch(m_tType) { - case MOVIE: + case MediaType::MOVIE: if(m_iYear > 0) { res = Poco::format("%s (%d)", m_sTitle, m_iYear); } else { res = m_sTitle; } break; - case EPISODE: + case MediaType::EPISODE: res = Poco::format("%s - %02dx%02d - %s", seriesTitle, m_iParentIndex, m_iIndex, m_sTitle); break; default: @@ -248,7 +264,7 @@ void Video::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool c grid->AddIntToken((int)(eTokenGridInt::viewoffsetpercent), 0); grid->AddIntToken((int)(eTokenGridInt::duration), m_iDuration/1000/60); grid->AddIntToken((int)(eTokenGridInt::year), m_iYear); - grid->AddIntToken((int)(eTokenGridInt::viewgroup), m_pParent->m_eViewGroup); + if(m_pParent) grid->AddIntToken((int)(eTokenGridInt::viewgroup), (int)m_pParent->m_eViewGroup); // Thumb, Cover, Episodepicture bool cached = false; @@ -262,8 +278,10 @@ void Video::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool c grid->AddIntToken((int)(eTokenGridInt::hasart), cached); if (cached) grid->AddStringToken((int)(eTokenGridStr::art), art.c_str()); - if(m_tType == MediaType::MOVIE || m_tType == MediaType::CLIP) { + if(m_tType == MediaType::MOVIE) { grid->AddIntToken((int)(eTokenGridInt::ismovie), true); + } else if (m_tType == MediaType::CLIP) { + grid->AddIntToken((int)(eTokenGridInt::isclip), true); } vector<int> loopInfo; @@ -47,6 +47,7 @@ class Video: private XmlObject private: MediaContainer* m_pParent; void Parse(Poco::XML::Node* pNode); + void ParseExtras(Poco::XML::Node* pNode); public: Video(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent); @@ -87,6 +88,8 @@ public: int m_iMyPlayOffset; int m_iIndex; int m_iParentIndex; + std::vector<Video> m_vExtras; + ExtraType m_eExtraType; virtual std::string GetTitle(); bool SetStream(Stream* stream); @@ -27,9 +27,9 @@ Stream::Stream(Poco::XML::Node* pNode) std::string Stream::GetSetStreamQuery() { - if(m_eStreamType == sAUDIO) return Poco::format("audioStreamID=%d", m_iID); - else if(m_eStreamType == sSUBTITLE && m_iID >= 0) return Poco::format("subtitleStreamID=%d", m_iID); - else if(m_eStreamType == sSUBTITLE && m_iID < 0) return "subtitleStreamID="; + if(m_eStreamType == StreamType::sAUDIO) return Poco::format("audioStreamID=%d", m_iID); + else if(m_eStreamType == StreamType::sSUBTITLE && m_iID >= 0) return Poco::format("subtitleStreamID=%d", m_iID); + else if(m_eStreamType == StreamType::sSUBTITLE && m_iID < 0) return "subtitleStreamID="; else return ""; } diff --git a/XmlObject.cpp b/XmlObject.cpp index e934980..8c01dd7 100644 --- a/XmlObject.cpp +++ b/XmlObject.cpp @@ -82,24 +82,24 @@ Poco::DateTime XmlObject::GetNodeValueAsDateTime(Poco::XML::Node* pNode) MediaType XmlObject::GetNodeValueAsMediaType(Poco::XML::Node* pNode) { - MediaType type = UNDEF; + MediaType type = MediaType::UNDEF; if(pNode != 0) { std::string sType = pNode->nodeValue(); if (Poco::icompare(sType, "photo") == 0) { - type = PHOTO; + type = MediaType::PHOTO; } else if (Poco::icompare(sType, "movie") == 0) { - type = MOVIE; + type = MediaType::MOVIE; } else if (Poco::icompare(sType, "music") == 0) { - type = MUSIC; + type = MediaType::MUSIC; } else if (Poco::icompare(sType, "show") == 0) { - type = SHOW; + type = MediaType::SHOW; } else if (Poco::icompare(sType, "season") == 0) { - type = SEASON; + type = MediaType::SEASON; } else if (Poco::icompare(sType, "episode") == 0) { - type = EPISODE; + type = MediaType::EPISODE; } else if (Poco::icompare(sType, "clip") == 0) { - type = CLIP; + type = MediaType::CLIP; } } return type; @@ -107,22 +107,60 @@ MediaType XmlObject::GetNodeValueAsMediaType(Poco::XML::Node* pNode) StreamType XmlObject::GetNodeValueAsStreamType(Poco::XML::Node* pNode) { - StreamType type = sUNDEF; + StreamType type = StreamType::sUNDEF; if(pNode != 0) { int iType = GetNodeValueAsInt(pNode); switch(iType) { case 1: - type = sVIDEO; + type = StreamType::sVIDEO; break; case 2: - type = sAUDIO; + type = StreamType::sAUDIO; break; case 3: - type = sSUBTITLE; + type = StreamType::sSUBTITLE; break; default: - type = sUNDEF; + type = StreamType::sUNDEF; + break; + } + } + return type; +} + +PlaylistType XmlObject::GetNodeValueAsPlaylistType(Poco::XML::Node* pNode) +{ + PlaylistType type = PlaylistType::Undef; + + if(pNode != 0) { + std::string sType = pNode->nodeValue(); + if (Poco::icompare(sType, "photo") == 0) { + type = PlaylistType::Photo; + } else if (Poco::icompare(sType, "video") == 0) { + type = PlaylistType::Video; + } else if (Poco::icompare(sType, "audio") == 0) { + type = PlaylistType::Audio; + } + } + return type; +} + +ExtraType XmlObject::GetNodeValueAsExtraType(Poco::XML::Node* pNode) +{ + ExtraType type = ExtraType::Unkown; + + if(pNode != 0) { + int iType = GetNodeValueAsInt(pNode); + switch(iType) { + case 1: + type = ExtraType::Trailer; + break; + case 5: + type = ExtraType::BehindTheScenes; + break; + default: + type = ExtraType::Unkown; break; } } diff --git a/XmlObject.h b/XmlObject.h index 9e65984..4c64a6c 100644 --- a/XmlObject.h +++ b/XmlObject.h @@ -13,8 +13,10 @@ namespace plexclient { -enum MediaType {UNDEF = 0, MOVIE, SHOW, SEASON, EPISODE, MUSIC, PHOTO, CLIP}; -enum StreamType {sUNDEF = 0, sVIDEO = 1, sAUDIO = 2, sSUBTITLE = 3}; +enum class MediaType {UNDEF = 0, MOVIE, SHOW, SEASON, EPISODE, MUSIC, PHOTO, CLIP, PLAYLIST}; +enum class PlaylistType { Undef, Video, Audio, Photo }; +enum class StreamType {sUNDEF = 0, sVIDEO = 1, sAUDIO = 2, sSUBTITLE = 3}; +enum class ExtraType { Unkown = 0, Trailer = 1, BehindTheScenes = 5 }; class XmlObject { @@ -28,6 +30,8 @@ protected: static Poco::DateTime GetNodeValueAsDateTime(Poco::XML::Node* pNode); static MediaType GetNodeValueAsMediaType(Poco::XML::Node* pNode); static StreamType GetNodeValueAsStreamType(Poco::XML::Node* pNode); + static PlaylistType GetNodeValueAsPlaylistType(Poco::XML::Node* pNode); + static ExtraType GetNodeValueAsExtraType(Poco::XML::Node* pNode); private: }; diff --git a/browserGrid.cpp b/browserGrid.cpp index 4163c08..b3ddb83 100644 --- a/browserGrid.cpp +++ b/browserGrid.cpp @@ -301,12 +301,9 @@ void cBrowserGrid::DrawFooter() } else if(m_viewEntryIndex + 1 == (int)Config::GetInstance().m_viewentries.size() + 1) { nextTab = Config::GetInstance().m_viewentries[0].Name.c_str(); } - cString prevTab = "Library"; - if(m_viewEntryIndex - 1 >= 0) { - prevTab = Config::GetInstance().m_viewentries[m_viewEntryIndex - 1].Name.c_str(); - } + cString details = "Details"; - string textGreen = tr(prevTab); + string textGreen = tr(details); string textYellow = tr(nextTab); string textRed = ""; string textBlue = tr("Switch View"); diff --git a/detailView.cpp b/detailView.cpp index ec7aee3..ef84179 100644 --- a/detailView.cpp +++ b/detailView.cpp @@ -1,10 +1,172 @@ #include "detailView.h" +#include "Config.h" -cDetailView::cDetailView(skindesignerapi::cOsdView *detailView, const cGridElement *element) +cDetailView::cDetailView(std::shared_ptr<skindesignerapi::cOsdView> detailView, plexclient::Video *video) + : cViewGridNavigator(detailView) { + m_pBackground = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::background)); + m_pfooter = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::footer)); + m_pInfo = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::info)); + m_pScrollbar = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::scrollbar)); + + m_pVideo = video; + m_drawall = true; + + m_pGrid = NULL; + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(detailView->GetViewGrid((int)eViewDetailViewGrids::extras))); + SetGridDimensions(Config::GetInstance().ExtrasGridColumns, Config::GetInstance().ExtrasGridRows); +} + +void cDetailView::Flush() +{ + if (m_drawall) { + m_pBackground->Display(); + m_pInfo->Display(); + m_drawall = false; + } + m_pfooter->Display(); + m_pGrid->Display(); + m_pScrollbar->Display(); +} + +void cDetailView::Draw() +{ + // Draw Grid + m_vElements.clear(); + + int pos = 0; + for(auto it = m_pVideo->m_vExtras.begin(); it != m_pVideo->m_vExtras.end(); ++it) { + plexclient::Video *elem = &(*it); + elem->AbsolutePosition = pos++;; + m_vElements.push_back(elem); + } + + m_startIndex = 0; + +// m_pGrid->Clear(); + m_setIterator = true; + FilterElements(0); + + DrawBackground(); + DrawFooter(); + DrawInfo(); + DrawScrollbar(); +} + +void cDetailView::Clear() +{ + m_pBackground->Clear(); + m_pInfo->Clear(); + m_pScrollbar->Clear(); + m_pfooter->Clear(); + m_pGrid->Clear(); +} + +void cDetailView::DrawBackground() +{ + m_pBackground->ClearTokens(); + bool art = m_pVideo->m_sArt.empty() == false; + m_pBackground->AddIntToken((int)eTokenDetailBackgroundInt::hasfanart, art); + if(art) m_pBackground->AddStringToken((int)eTokenDetailBackgroundStr::fanartpath, m_pVideo->m_sArt.c_str()); + + bool cover = m_pVideo->m_sThumb.empty() == false; + m_pBackground->AddIntToken((int)eTokenDetailBackgroundInt::hascover, cover); + if(Cover) m_pBackground->AddStringToken((int)eTokenDetailBackgroundStr::coverpath, m_pVideo->m_sThumb.c_str()); +} + +void cDetailView::DrawFooter() +{ + string textGreen = ""; + string textYellow = ""; + string textRed = ""; + string textBlue = "Play"; + + if(auto vid = dynamic_cast<plexclient::Video*>(SelectedObject()) ) { + if(vid->m_iViewCount > 0) textRed = tr("Unscrobble"); + else textRed = tr("Scrobble"); + } + + + int colorKeys[4] = { Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3 }; + + m_pfooter->Clear(); + m_pfooter->ClearTokens(); + + m_pfooter->AddStringToken((int)eTokenFooterStr::red, textRed.c_str()); + m_pfooter->AddStringToken((int)eTokenFooterStr::green, textGreen.c_str()); + m_pfooter->AddStringToken((int)eTokenFooterStr::yellow, textYellow.c_str()); + m_pfooter->AddStringToken((int)eTokenFooterStr::blue, textBlue.c_str()); + + for (int button = 0; button < 4; button++) { + bool isRed = false; + bool isGreen = false; + bool isYellow = false; + bool isBlue = false; + switch (colorKeys[button]) { + case 0: + isRed = true; + break; + case 1: + isGreen = true; + break; + case 2: + isYellow = true; + break; + case 3: + isBlue = true; + break; + default: + break; + } + m_pfooter->AddIntToken(0 + button, isRed); + m_pfooter->AddIntToken(4 + button, isGreen); + m_pfooter->AddIntToken(8 + button, isYellow); + m_pfooter->AddIntToken(12 + button, isBlue); + } + + m_pfooter->Display(); } -cDetailView::~cDetailView() +void cDetailView::DrawInfo() { + m_pInfo->Clear(); + m_pVideo->AddTokens(m_pInfo, true); + m_pInfo->Display(); } +void cDetailView::DrawScrollbar() +{ + if (m_vElements.size() == 0) + return; + + int currentRow = SelectedObject()->AbsolutePosition / m_columns; + int totalRows = m_vElements.size() / m_columns; + + int scrollBarHeight = 100.0 / totalRows * m_rows; + + int offset = 100.0 / totalRows * currentRow; + if(offset >= 100 - scrollBarHeight) { + offset = 100.0 - scrollBarHeight; + } + m_pScrollbar->Clear(); + m_pScrollbar->ClearTokens(); + + m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::height, scrollBarHeight); + m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::offset, offset); + m_pScrollbar->Display(); +} + +eOSState cDetailView::NavigateSelect() +{ + if(m_setIterator) return eOSState::osContinue; + + if(dynamic_cast<plexclient::Video*>(SelectedObject())) { + return eOSState::osUser1; + } else return eOSState::osBack; +} + +eOSState cDetailView::NavigateBack() +{ + if(m_setIterator) return eOSState::osContinue;; + return eOSState::osBack; +} diff --git a/detailView.h b/detailView.h index d72e6d4..cc5f156 100644 --- a/detailView.h +++ b/detailView.h @@ -2,13 +2,37 @@ #define CDETAILVIEW_H #include "viewGridNavigator.h" +#include "PVideo.h" -class cDetailView +#include "tokendefinitions.h" +#include <libskindesignerapi/osdelements.h> +#include <libskindesignerapi/skindesignerosdbase.h> + +class cDetailView : public cViewGridNavigator { public: - cDetailView(skindesignerapi::cOsdView *detailView, const cGridElement *element); - ~cDetailView(); + cDetailView(std::shared_ptr<skindesignerapi::cOsdView> detailView, plexclient::Video *video); + + void Draw(); + void Flush(); + virtual eOSState NavigateSelect(); + virtual eOSState NavigateBack(); + plexclient::Video* GetVideo() { return m_pVideo; }; + virtual void Clear(); + +private: + std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; + std::shared_ptr<skindesignerapi::cViewElement> m_pfooter; + std::shared_ptr<skindesignerapi::cViewElement> m_pInfo; + std::shared_ptr<skindesignerapi::cViewElement> m_pScrollbar; + + plexclient::Video *m_pVideo; + bool m_drawall; + void DrawBackground(); + void DrawFooter(); + void DrawInfo(); + void DrawScrollbar(); }; #endif // CDETAILVIEW_H diff --git a/hlsPlayer.cpp b/hlsPlayer.cpp index fc05479..e58eb28 100644 --- a/hlsPlayer.cpp +++ b/hlsPlayer.cpp @@ -484,7 +484,7 @@ void cHlsPlayer::SetAudioAndSubtitleTracks(void) std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::sAUDIO) { + if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { DeviceSetAvailableTrack(ttDolby, pStream->m_iIndex, pStream->m_iIndex + AudioIndexOffset, pStream->m_sLanguage.c_str(), pStream->m_sCodec.c_str()); } } @@ -668,7 +668,7 @@ void cHlsPlayer::SetAudioTrack(eTrackType Type __attribute__((unused)), const tT std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::sAUDIO && pStream->m_iIndex + AudioIndexOffset == TrackId->id) { + if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO && pStream->m_iIndex + AudioIndexOffset == TrackId->id) { streamId = pStream->m_iID; break; } diff --git a/hlsPlayerControl.cpp b/hlsPlayerControl.cpp index b7acd24..7a2467b 100644 --- a/hlsPlayerControl.cpp +++ b/hlsPlayerControl.cpp @@ -332,7 +332,7 @@ void cStreamSelectMenu::CreateMenu() Add(new cOsdItem(tr("Audiostreams"), osUnknown, false)); for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::sAUDIO) { + if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { // Audio cString item = cString::sprintf(tr("%s%s - %s %d Channels"), pStream->m_bSelected ? "[*] ":"", pStream->m_sLanguage.c_str(), pStream->m_sCodecId.c_str(), pStream->m_iChannels); Add(new cPlexOsdItem(item, pStream)); @@ -341,12 +341,12 @@ void cStreamSelectMenu::CreateMenu() Add(new cOsdItem(tr("Subtitlestreams"), osUnknown, false)); plexclient::Stream stre; - stre.m_eStreamType = plexclient::sSUBTITLE; + stre.m_eStreamType = plexclient::StreamType::sSUBTITLE; stre.m_iID = -1; Add(new cPlexOsdItem(tr("None"), &stre)); for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::sSUBTITLE) { + if(pStream->m_eStreamType == plexclient::StreamType::sSUBTITLE) { // Subtitle cString item = cString::sprintf("%s%s", pStream->m_bSelected ? "[*] ":"", pStream->m_sLanguage.c_str()); Add(new cPlexOsdItem(item, pStream)); @@ -109,7 +109,32 @@ bool cMyPlugin::Start(void) m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::cover, "coverbrowser", tkGridCover); m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::detail, "detailbrowser", tkGridDetail); m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::list, "listbrowser", tkGridList); - + + // DetailsView + m_pPlugStruct->RegisterSubView((int)eViews::detailView, "detail.xml"); + skindesignerapi::cTokenContainer *tkBackgroundDetail = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::background, tkBackgroundDetail); + m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::background, "background", tkBackgroundDetail); + + skindesignerapi::cTokenContainer *tkDetailInfo = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::info, tkDetailInfo); + m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::info, "info", tkDetailInfo); + + skindesignerapi::cTokenContainer *tkDetailFooter = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::footer, tkDetailFooter); + m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::footer, "footer", tkDetailFooter); + + skindesignerapi::cTokenContainer *tkDetailScrollbar = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::scrollbar, tkDetailScrollbar); + m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::scrollbar, "scrollbar", tkDetailScrollbar); + + skindesignerapi::cTokenContainer *tkDetailMessage = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::message, tkDetailMessage); + m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::message, "message", tkDetailMessage); + + skindesignerapi::cTokenContainer *tkDetailExtraGrid = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineGridTokens(tkDetailExtraGrid); + m_pPlugStruct->RegisterViewGrid((int)eViews::detailView, (int)eViewDetailViewGrids::extras, "extragrid", tkDetailExtraGrid); if (!skindesignerapi::SkindesignerAPI::RegisterPlugin(m_pPlugStruct)) { esyslog("[plex]: skindesigner not available"); diff --git a/plexSdOsd.cpp b/plexSdOsd.cpp index b078879..1515ccd 100644 --- a/plexSdOsd.cpp +++ b/plexSdOsd.cpp @@ -50,13 +50,20 @@ void cPlexSdOsd::Show(void) m_pBrowserGrid = std::shared_ptr<cBrowserGrid>(new cBrowserGrid(m_pRootView)); m_pMessage = std::shared_ptr<skindesignerapi::cViewElement>(m_pRootView->GetViewElement((int)eViewElementsRoot::message)); m_messageDisplayed = false; + m_detailsActive = false; Flush(); } void cPlexSdOsd::Flush() { - m_pBrowserGrid->DrawGrid(); - m_pBrowserGrid->Flush(); + if(m_detailsActive) { + m_pDetailGrid->Draw(); + m_pDetailGrid->Flush(); + } + else { + m_pBrowserGrid->DrawGrid(); + m_pBrowserGrid->Flush(); + } } eOSState cPlexSdOsd::ProcessKey(eKeys Key) @@ -97,6 +104,50 @@ eOSState cPlexSdOsd::ProcessKey(eKeys Key) default: break; } + } else if(m_detailsActive) { + switch (Key & ~k_Repeat) { + case kUp: + if(m_pDetailGrid->NavigateUp()) Flush(); + break; + case kDown: + if(m_pDetailGrid->NavigateDown()) Flush(); + break; + case kLeft: + if(m_pDetailGrid->NavigateLeft()) Flush(); + break; + case kRight: + if(m_pDetailGrid->NavigateRight()) Flush(); + break; + case kOk: + state = m_pDetailGrid->NavigateSelect(); + Flush(); + break; + case kBack: + state = m_pDetailGrid->NavigateBack(); + m_pDetailGrid->Clear(); + m_pDetailsView->Deactivate(true); + m_pDetailGrid = nullptr; + m_pDetailsView = nullptr; + m_detailsActive = false; + m_pRootView->Activate(); + break; + case kBlue: + vid = m_pDetailGrid->GetVideo(); + state = eOSState::osUser1; + break; + case kRed: + if(m_pDetailGrid->GetVideo()) { + if(m_pDetailGrid->GetVideo()->m_iViewCount > 0) m_pDetailGrid->GetVideo()->SetUnwatched(); + else m_pDetailGrid->GetVideo()->SetWatched(); + m_pDetailGrid->GetVideo()->UpdateFromServer(); + Flush(); + } + break; + case kGreen: + case kYellow: + default: + break; + } } else { switch (Key & ~k_Repeat) { @@ -115,6 +166,9 @@ eOSState cPlexSdOsd::ProcessKey(eKeys Key) case kOk: // Play movie or change dir state = m_pBrowserGrid->NavigateSelect(); + if(state == eOSState::osUser1) { + vid = dynamic_cast<plexclient::Video*>(m_pBrowserGrid->SelectedObject()); + } Flush(); break; case kBack: @@ -134,9 +188,13 @@ eOSState cPlexSdOsd::ProcessKey(eKeys Key) Flush(); } break; - case kGreen: - m_pBrowserGrid->PrevTab(); - Flush(); + case kGreen: // Show Details OSD + vid = dynamic_cast<plexclient::Video*>(m_pBrowserGrid->SelectedObject()); + if(vid) { + vid->UpdateFromServer(); + ShowDetails(vid); + //Flush(); + } break; case kYellow: m_pBrowserGrid->NextTab(); @@ -149,7 +207,6 @@ eOSState cPlexSdOsd::ProcessKey(eKeys Key) } if(state == eOSState::osUser1) { - vid = dynamic_cast<plexclient::Video*>(m_pBrowserGrid->SelectedObject()); if(vid->m_iMyPlayOffset == 0 && vid->m_lViewoffset > 0 ) { cString message = cString::sprintf(tr("'Ok' to start from %ld minutes, 'Back' to start from beginning."), vid->m_lViewoffset / 60000); DrawMessage(std::string(message)); @@ -162,6 +219,20 @@ eOSState cPlexSdOsd::ProcessKey(eKeys Key) return state; } +void cPlexSdOsd::ShowDetails(plexclient::Video *vid) +{ + if(m_detailsActive) return; + + m_pRootView->Deactivate(true); + m_pDetailsView = std::shared_ptr<skindesignerapi::cOsdView>(GetOsdView((int)eViews::detailView)); + m_pDetailGrid = std::shared_ptr<cDetailView>(new cDetailView(m_pDetailsView, vid)); + + m_pDetailGrid->Draw(); + m_pDetailGrid->Flush(); + m_detailsActive = true; + +} + void cPlexSdOsd::DrawMessage(std::string message) { m_pMessage->ClearTokens(); @@ -186,41 +257,10 @@ void cPlexSdOsd::DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenConta tk->DefineStringToken("{tabname}", (int)eTokenGridStr::tabname); break; case eViewElementsRoot::footer: - tk->DefineIntToken("{red1}", (int)eTokenFooterInt::red1); - tk->DefineIntToken("{red2}", (int)eTokenFooterInt::red2); - tk->DefineIntToken("{red3}", (int)eTokenFooterInt::red3); - tk->DefineIntToken("{red4}", (int)eTokenFooterInt::red4); - tk->DefineIntToken("{green1}", (int)eTokenFooterInt::green1); - tk->DefineIntToken("{green2}", (int)eTokenFooterInt::green2); - tk->DefineIntToken("{green3}", (int)eTokenFooterInt::green3); - tk->DefineIntToken("{green4}", (int)eTokenFooterInt::green4); - tk->DefineIntToken("{yellow1}", (int)eTokenFooterInt::yellow1); - tk->DefineIntToken("{yellow2}", (int)eTokenFooterInt::yellow2); - tk->DefineIntToken("{yellow3}", (int)eTokenFooterInt::yellow3); - tk->DefineIntToken("{yellow4}", (int)eTokenFooterInt::yellow4); - tk->DefineIntToken("{blue1}", (int)eTokenFooterInt::blue1); - tk->DefineIntToken("{blue2}", (int)eTokenFooterInt::blue2); - tk->DefineIntToken("{blue3}", (int)eTokenFooterInt::blue3); - tk->DefineIntToken("{blue4}", (int)eTokenFooterInt::blue4); - tk->DefineStringToken("{red}", (int)eTokenFooterStr::red); - tk->DefineStringToken("{green}", (int)eTokenFooterStr::green); - tk->DefineStringToken("{yellow}", (int)eTokenFooterStr::yellow); - tk->DefineStringToken("{blue}", (int)eTokenFooterStr::blue); + DefineFooterTokens(tk); break; case eViewElementsRoot::watch: - tk->DefineIntToken("{sec}", (int)eTokenTimeInt::sec); - tk->DefineIntToken("{min}", (int)eTokenTimeInt::min); - tk->DefineIntToken("{hour}", (int)eTokenTimeInt::hour); - tk->DefineIntToken("{hmins}", (int)eTokenTimeInt::hmins); - tk->DefineIntToken("{day}", (int)eTokenTimeInt::day); - tk->DefineIntToken("{year}", (int)eTokenTimeInt::year); - tk->DefineStringToken("{time}", (int)eTokenTimeStr::time); - tk->DefineStringToken("{dayname}", (int)eTokenTimeStr::dayname); - tk->DefineStringToken("{daynameshort}", (int)eTokenTimeStr::daynameshort); - tk->DefineStringToken("{dayleadingzero}", (int)eTokenTimeStr::dayleadingzero); - tk->DefineStringToken("{month}", (int)eTokenTimeStr::month); - tk->DefineStringToken("{monthname}", (int)eTokenTimeStr::monthname); - tk->DefineStringToken("{monthnameshort}", (int)eTokenTimeStr::monthnameshort); + DefineWatchTokens(tk); break; case eViewElementsRoot::message: tk->DefineIntToken("{displaymessage}", (int)eTokenMessageInt::displaymessage); @@ -250,6 +290,7 @@ void cPlexSdOsd::DefineGridTokens(skindesignerapi::cTokenContainer* tk) tk->DefineIntToken("{isdirectory}", (int)eTokenGridInt::isdirectory); tk->DefineIntToken("{isshow}", (int)eTokenGridInt::isshow); tk->DefineIntToken("{isseason}", (int)eTokenGridInt::isseason); + tk->DefineIntToken("{isclip}", (int)eTokenGridInt::isclip); tk->DefineIntToken("{originallyAvailableYear}", (int)eTokenGridInt::originallyAvailableYear); tk->DefineIntToken("{originallyAvailableMonth}", (int)eTokenGridInt::originallyAvailableMonth); tk->DefineIntToken("{originallyAvailableDay}", (int)eTokenGridInt::originallyAvailableDay); @@ -297,3 +338,72 @@ void cPlexSdOsd::DefineGridTokens(skindesignerapi::cTokenContainer* tk) tk->DefineLoopToken("{roles[actor]}", (int)eTokenGridActorLst::roles); tk->DefineLoopToken("{genres[genre]}", (int)eTokenGridGenresLst::genres); } + +void cPlexSdOsd::DefineFooterTokens(skindesignerapi::cTokenContainer *tk) +{ + tk->DefineIntToken("{red1}", (int)eTokenFooterInt::red1); + tk->DefineIntToken("{red2}", (int)eTokenFooterInt::red2); + tk->DefineIntToken("{red3}", (int)eTokenFooterInt::red3); + tk->DefineIntToken("{red4}", (int)eTokenFooterInt::red4); + tk->DefineIntToken("{green1}", (int)eTokenFooterInt::green1); + tk->DefineIntToken("{green2}", (int)eTokenFooterInt::green2); + tk->DefineIntToken("{green3}", (int)eTokenFooterInt::green3); + tk->DefineIntToken("{green4}", (int)eTokenFooterInt::green4); + tk->DefineIntToken("{yellow1}", (int)eTokenFooterInt::yellow1); + tk->DefineIntToken("{yellow2}", (int)eTokenFooterInt::yellow2); + tk->DefineIntToken("{yellow3}", (int)eTokenFooterInt::yellow3); + tk->DefineIntToken("{yellow4}", (int)eTokenFooterInt::yellow4); + tk->DefineIntToken("{blue1}", (int)eTokenFooterInt::blue1); + tk->DefineIntToken("{blue2}", (int)eTokenFooterInt::blue2); + tk->DefineIntToken("{blue3}", (int)eTokenFooterInt::blue3); + tk->DefineIntToken("{blue4}", (int)eTokenFooterInt::blue4); + tk->DefineStringToken("{red}", (int)eTokenFooterStr::red); + tk->DefineStringToken("{green}", (int)eTokenFooterStr::green); + tk->DefineStringToken("{yellow}", (int)eTokenFooterStr::yellow); + tk->DefineStringToken("{blue}", (int)eTokenFooterStr::blue); +} + +void cPlexSdOsd::DefineWatchTokens(skindesignerapi::cTokenContainer *tk) +{ + tk->DefineIntToken("{sec}", (int)eTokenTimeInt::sec); + tk->DefineIntToken("{min}", (int)eTokenTimeInt::min); + tk->DefineIntToken("{hour}", (int)eTokenTimeInt::hour); + tk->DefineIntToken("{hmins}", (int)eTokenTimeInt::hmins); + tk->DefineIntToken("{day}", (int)eTokenTimeInt::day); + tk->DefineIntToken("{year}", (int)eTokenTimeInt::year); + tk->DefineStringToken("{time}", (int)eTokenTimeStr::time); + tk->DefineStringToken("{dayname}", (int)eTokenTimeStr::dayname); + tk->DefineStringToken("{daynameshort}", (int)eTokenTimeStr::daynameshort); + tk->DefineStringToken("{dayleadingzero}", (int)eTokenTimeStr::dayleadingzero); + tk->DefineStringToken("{month}", (int)eTokenTimeStr::month); + tk->DefineStringToken("{monthname}", (int)eTokenTimeStr::monthname); + tk->DefineStringToken("{monthnameshort}", (int)eTokenTimeStr::monthnameshort); +} + +void cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk) +{ + switch(ve) { + case eViewElementsDetail::background: + tk->DefineIntToken("{hasfanart}", (int)eTokenDetailBackgroundInt::hasfanart); + tk->DefineIntToken("{hascover}", (int)eTokenDetailBackgroundInt::hascover); + tk->DefineStringToken("{fanartpath}", (int)eTokenDetailBackgroundStr::fanartpath); + tk->DefineStringToken("{coverpath}", (int)eTokenDetailBackgroundStr::coverpath); + break; + case eViewElementsDetail::footer: + DefineFooterTokens(tk); + break; + case eViewElementsDetail::info: + DefineGridTokens(tk); + break; + case eViewElementsDetail::message: + tk->DefineIntToken("{displaymessage}", (int)eTokenMessageInt::displaymessage); + tk->DefineStringToken("{message}", (int)eTokenMessageStr::message); + break; + case eViewElementsDetail::scrollbar: + tk->DefineIntToken("{height}", (int)eTokenScrollbarInt::height); + tk->DefineIntToken("{offset}", (int)eTokenScrollbarInt::offset); + break; + default: + break; + } +}
\ No newline at end of file diff --git a/plexSdOsd.h b/plexSdOsd.h index 0899869..73c7885 100644 --- a/plexSdOsd.h +++ b/plexSdOsd.h @@ -17,6 +17,7 @@ #include "hlsPlayerControl.h" #include "browserGrid.h" +#include "detailView.h" #include "tokendefinitions.h" #include <libskindesignerapi/osdelements.h> #include <libskindesignerapi/skindesignerosdbase.h> @@ -25,10 +26,13 @@ class cPlexSdOsd : public skindesignerapi::cSkindesignerOsdObject { private: std::shared_ptr<cBrowserGrid> m_pBrowserGrid; + std::shared_ptr<cDetailView> m_pDetailGrid; std::shared_ptr<skindesignerapi::cViewElement> m_pMessage; bool m_messageDisplayed; + bool m_detailsActive; std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; + std::shared_ptr<skindesignerapi::cOsdView> m_pDetailsView; void Flush(); //void SwitchGrid(ePlexMenuTab currentTab); @@ -36,6 +40,8 @@ private: void DrawFooter(); void DrawMessage(std::string message); + void ShowDetails(plexclient::Video *vid); + public: cPlexSdOsd(skindesignerapi::cPluginStructure *plugStruct); ~cPlexSdOsd(); @@ -46,6 +52,9 @@ public: static cMutex RedrawMutex; static void DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer *tk); static void DefineGridTokens(skindesignerapi::cTokenContainer *tk); + static void DefineFooterTokens(skindesignerapi::cTokenContainer *tk); + static void DefineWatchTokens(skindesignerapi::cTokenContainer *tk); + static void DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk); }; #endif // CPLEXSDOSD_H diff --git a/templates/plug-plex-root.xml b/templates/plug-plex-root.xml index a6c3e30..efa8ae1 100644 --- a/templates/plug-plex-root.xml +++ b/templates/plug-plex-root.xml @@ -110,7 +110,7 @@ If the item is a video following tokens are avaliable - The item is a video if one of the following tokens are set: {ismovie}, {isepisode} + The item is a video if one of the following tokens are set: {ismovie}, {isepisode}, {isclip} {contentrating} string, FSK, PEGI -> eg. de/16 {rating} int, starrating 0.0 - 10.0 multiplied by 10 -> 0 - 100 {ratingstring} string, rating formated as double %.1f diff --git a/tokendefinitions.h b/tokendefinitions.h index 52f17cd..55dd270 100644 --- a/tokendefinitions.h +++ b/tokendefinitions.h @@ -6,6 +6,14 @@ enum class eViews { detailView }; +enum class eViewElementsDetail { + background, + footer, + info, + message, + scrollbar +}; + enum class eViewElementsRoot { background, header, @@ -19,13 +27,11 @@ enum class eViewElementsRoot { enum class eViewGrids { cover, detail, - list + list, }; -enum class eViewElementsDetail { - background, - header, - footer +enum class eViewDetailViewGrids { + extras }; enum class eTokenGridInt { @@ -43,6 +49,7 @@ enum class eTokenGridInt { isdirectory, isshow, isseason, + isclip, originallyAvailableYear, originallyAvailableMonth, originallyAvailableDay, @@ -122,6 +129,16 @@ enum class eTokenBackgroundStr { currentdirectorybackground }; +enum class eTokenDetailBackgroundInt { + hasfanart = 0, + hascover +}; + +enum class eTokenDetailBackgroundStr { + fanartpath = 0, + coverpath +}; + enum class eTokenTimeInt { sec = 0, min, diff --git a/viewGridNavigator.h b/viewGridNavigator.h index 2622c48..ea5a3f5 100644 --- a/viewGridNavigator.h +++ b/viewGridNavigator.h @@ -48,7 +48,6 @@ protected: int m_startIndex; int m_endIndex; - void GenerateServerElements(); void FilterElements(int scrollOffset); void SetGridElementData(cGridElement *obj); void SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid> grid); |