Skip to content

Commit

Permalink
Beginnings of Live TV & DVR Support
Browse files Browse the repository at this point in the history
  • Loading branch information
SheaSmith committed Nov 3, 2019
1 parent 11c5fd4 commit 6ebd929
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def dinit(src, param, newlog=False):


def dprint(src, dlevel, *args):
logToTerminal = not (src in dlevels) or dlevel <= dlevels[src]
logToTerminal = True
logToFile = not g_loglevel==-1 and not g_logfile=='' and dlevel <= g_loglevel

if logToTerminal or logToFile:
Expand Down
36 changes: 26 additions & 10 deletions PlexAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ def getXMLFromMultiplePMS(ATV_udid, path, type, options={}):
(data, XML) = queue.get()
uuid = data['uuid']
Server = data['Server']

baseURL = getPMSProperty(ATV_udid, uuid, 'baseURL')
token = getPMSProperty(ATV_udid, uuid, 'accesstoken')
PMS_mark = 'PMS(' + getPMSProperty(ATV_udid, uuid, 'address') + ')'
Expand All @@ -565,15 +565,31 @@ def getXMLFromMultiplePMS(ATV_udid, path, type, options={}):
Server.set('size', XML.getroot().get('size', '0'))

for Dir in XML.getiterator('Directory'): # copy "Directory" content, add PMS to links
key = Dir.get('key') # absolute path
Dir.set('key', PMS_mark + getURL('', path, key))
Dir.set('refreshKey', getURL(baseURL, path, key) + '/refresh')
if 'thumb' in Dir.attrib:
Dir.set('thumb', PMS_mark + getURL('', path, Dir.get('thumb')))
if 'art' in Dir.attrib:
Dir.set('art', PMS_mark + getURL('', path, Dir.get('art')))
Server.append(Dir)

if Dir.get('key') is not None and Dir.get('agent') is not None:
key = Dir.get('key') # absolute path
Dir.set('key', PMS_mark + getURL('', path, key))
Dir.set('refreshKey', getURL(baseURL, path, key) + '/refresh')
if 'thumb' in Dir.attrib:
Dir.set('thumb', PMS_mark + getURL('', path, Dir.get('thumb')))
if 'art' in Dir.attrib:
Dir.set('art', PMS_mark + getURL('', path, Dir.get('art')))
print Dir.get('type')
Server.append(Dir)
elif Dir.get('title') == 'Live TV & DVR':
mp = None
for MediaProvider in XML.getiterator('MediaProvider'):
if MediaProvider.get('protocols') == 'livetv':
mp = MediaProvider
break

if mp is not None:
Dir.set('key', PMS_mark + getURL('', '', mp.get('identifier')))
Dir.set('refreshKey', getURL(baseURL, '/livetv/dvrs', mp.get('parentID')) + '/reloadGuide')
Dir.set('scanner', 'PlexConnect LiveTV Scanner Placeholder')
Dir.set('type', 'livetv')
Dir.set('thumbType', 'video')
Server.append(Dir)

for Playlist in XML.getiterator('Playlist'): # copy "Playlist" content, add PMS to links
key = Playlist.get('key') # absolute path
Playlist.set('key', PMS_mark + getURL('', path, key))
Expand Down
4 changes: 4 additions & 0 deletions WebServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import signal
import traceback

import datetime

import Settings, ATVSettings
from Debug import * # dprint()
import XMLConverter # XML_PMS2aTV, XML_PlayVideo
Expand Down Expand Up @@ -136,6 +138,8 @@ def do_GET(self):

# get aTV language setting
options['aTVLanguage'] = Localize.pickLanguage(self.headers.get('Accept-Language', 'en'))

query = query.replace("yyltyy", "<").replace("yygtyy", ">")

# add client address - to be used in case UDID is unknown
if 'X-Forwarded-For' in self.headers:
Expand Down
9 changes: 9 additions & 0 deletions XMLConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import string, random
import copy # deepcopy()

import datetime

try:
import xml.etree.cElementTree as etree
except ImportError:
Expand Down Expand Up @@ -347,6 +349,7 @@ def XML_PMS2aTV(PMS_address, path, options):
elif cmd.find('Photo') != -1: dir = 'Photo'
elif cmd.find('Premium_Music') != -1: dir = 'Music'
elif cmd.find('Music') != -1 or cmd.find('iTunes') != -1: dir ='Music'
elif cmd.find('LiveTV') != -1: dir = 'LiveTV'
else:
return XML_Error('PlexConnect', 'Unknown scanner: '+cmd)

Expand Down Expand Up @@ -618,6 +621,12 @@ def getParam(self, src, param):
param = param.replace('&lt;','<')
param = param.replace('&gt;','>')
param = param.replace('&amp;','&') # must be last

sevenDate = datetime.datetime.now().replace(hour=19)
elevenDate = datetime.datetime.now().replace(hour=23)

param = param.replace("7pmtimestamp", str(int(time.mktime(sevenDate.timetuple()))))
param = param.replace("11pmtimestamp", str(int(time.mktime(elevenDate.timetuple()))))

dprint(__name__, 2, "CCmds_getParam: {0}, {1}", param, leftover)
return [param, leftover]
Expand Down
12 changes: 12 additions & 0 deletions assets/templates/LiveTV/Grid.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<atv>
<body>
<search id="plex-search">
<header>
<simpleHeader>
<title>lol</title>
</simpleHeader>
</header>
</search>
</body>
</atv>
62 changes: 62 additions & 0 deletions assets/templates/LiveTV/Hub.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<atv>
<head>
<script src="{{URL(:/js/utils.js)}}"/>
</head>

<body>


<scroller id="com.sample.movie-showcase-grid">
<header>
<simpleHeader>
<title>Recommended</title>
</simpleHeader>
</header>

<items>
<__COPY__>
{{COPY(Hub)}}
<collectionDivider alignment="left" accessibilityLabel="{{VAL(title)}}">
<title>{{VAL(title)}}</title>
</collectionDivider>
<shelf id="{{VAL(hubKey)}}" columnCount="7">
<sections>
<shelfSection>
<items>
<moviePoster id="{{VAL(key)}}" accessibilityLabel="{{VAL(title)}}"
alwaysShowTitles="{{VAL($postertitles::Highlighted Only=false|Show All=true)}}"
onPlay="atv.loadURL('{{URL(key:::PlexConnect={{VAL(Media/onAir:LiveTV_Record:1=LiveTV_Watch|=LiveTV_Record)}}&amp;PlexConnectRatingKey={{VAL(ratingKey)}})}}')"
onSelect="atv.loadURL('{{URL(key:::includeExtras=1&amp;PlexConnect=Movie_PrePlay{{VAL($fanart::Hide=|Show=_Fanart)}})}}')"
onHoldSelect="scrobbleMenu('{{URL(key:::PlexConnect=Scrobble_MenuVideo)}}')">
{{COPY(Video)}}
<title>{{VAL(grandparentTitle)}}</title>{{CUT(grandparentTitle:CUT:=CUT| =)}}
<title>{{VAL(title)}}</title>{{CUT(grandparentTitle:: =CUT)}}
<subtitle>{{VAL(title)}}</subtitle>{{CUT(grandparentTitle:CUT:=CUT| =)}}
<image>{{IMAGEURL(grandparentThumb::384)}}</image>{{CUT(grandparentThumb:CUT:=CUT| =)}}
<image>{{IMAGEURL(thumb::384)}}</image>{{CUT(grandparentThumb:: =CUT)}}
<defaultImage>resource://Poster.png</defaultImage>
<badgeCount>8</badgeCount>
</moviePoster>

<moviePoster id="{{VAL(key)}}" accessibilityLabel="{{VAL(title)}}"
alwaysShowTitles="{{VAL($postertitles::Highlighted Only=false|Show All=true)}}"
onPlay="atv.loadURL('{{URL(key:::PlexConnect=Play_Video&amp;PlexConnectRatingKey={{VAL(ratingKey)}})}}')"
onSelect="atv.loadURL('{{URL(key:::includeExtras=1&amp;PlexConnect=Movie_PrePlay{{VAL($fanart::Hide=|Show=_Fanart)}})}}')"
onHoldSelect="scrobbleMenu('{{URL(key:::PlexConnect=Scrobble_MenuVideo)}}')">
{{COPY(Directory)}}
<title>{{VAL(title)}}</title>
<image>{{IMAGEURL(grandparentThumb::384)}}</image>{{CUT(grandparentThumb:CUT:=CUT| =)}}
<image>{{IMAGEURL(thumb::384)}}</image>{{CUT(grandparentThumb:: =CUT)}}
<defaultImage>resource://Poster.png</defaultImage>
</moviePoster>
</items>
</shelfSection>
</sections>
</shelf>
</__COPY__>
</items>
</scroller>


</body>
</atv>
65 changes: 65 additions & 0 deletions assets/templates/LiveTV/NavigationBar.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<atv>
<head>
<script src="{{URL(:/js/utils.js)}}" />
<script src="{{URL(:/js/updateXML.js)}}" />
</head>

<body>
<viewWithNavigationBar id="PlexConnect_Navigation" onNavigate="loadItem(event)" volatile="true" onVolatileReload="updatePage('{{URL(:::PlexConnect=LiveTV)}}');">
<navigation currentIndex="0">

<navigationItem id="0">
<title>Recommended</title>
<url>{{URL(key::/hubs/discover:excludeFields=summary&amp;count=20&amp;PlexConnect=LiveTV_Hub)}}</url>
</navigationItem>

<navigationItem id="1">
<title>On Right Now</title>
<url>{{URL(key::/all:type=1,4&amp;beginsAtyyltyy=now&amp;endsAtyygtyy=1sPlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="2">
<title>Starting Soon</title>
<url>{{URL(key::/all:type=1,4&amp;beginsAtyygtyy=+1s&amp;beginsAtyyltyy=+1hPlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="3">
<title>New Episodes Tonight</title>
<url>{{URL(key::/all:type=1,4&amp;beginsAtyygtyy=7pmtimestamp&amp;beginsAtyyltyy=11pmtimestamp&amp;sort=beginsAtPlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="4">
<title>Recommended for You</title>
<url>{{URL(key::/rec:PlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="5">
<title>Upcoming Movies</title>
<url>{{URL(key::/sections/1/all:type=1&amp;beginsAtyygtyy=now&amp;PlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="6">
<title>Upcoming Shows</title>
<url>{{URL(key::/sections/2/all:type=4&amp;beginsAtyygtyy=now&amp;PlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="7">
<title>Upcoming Sports</title>
<url>{{URL(key::/sections/3/all:type=4&amp;beginsAtyygtyy=now&amp;PlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="8">
<title>Upcoming News</title>
<url>{{URL(key::/sections/4/all:type=4&amp;beginsAtyygtyy=now&amp;PlexConnect=LiveTV_Grid)}}</url>
</navigationItem>

<navigationItem id="9">
<title>DVR Schedule</title>
<url>{{URL(/media/subscriptions/scheduled:::PlexConnect=LiveTV_DVRSchedule)}}</url>
</navigationItem>


</navigation>
</viewWithNavigationBar>
</body>
</atv>
21 changes: 21 additions & 0 deletions assets/templates/Main/SectionPreview-livetv.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<atv>
<body>
<preview>
<paradePreview inOrder="true">
<image>
{{COPY(Video:grandparentThumb::=COPY)}}
{{IMAGEURL(grandparentThumb::768)}}
</image>
</paradePreview>{{CUT(size:CUT:0=CUT|0 =|1=CUT|1 =|2=CUT|2 =|3=CUT|4=CUT|5=CUT|6=)}}

<crossFadePreview>
<image>
{{COPY(Video:grandparentThumb::=COPY)}}
{{IMAGEURL(grandparentThumb::768)}}
</image>
</crossFadePreview>{{CUT(size::0=|0 =CUT|1=|1 =CUT|2=|2 =CUT|3=|4=|5=|6=CUT)}}
</preview>
</body>
</atv>

2 changes: 1 addition & 1 deletion assets/templates/PlexConnect.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</navigationItem>{{CUT($playlistsview:CUT:=|Hide=CUT|Hide =)}}
<navigationItem id="Library">
<title>{{TEXT(Library)}}</title>
<url>{{URL(:/PMS(owned)/library/sections::PlexConnect=Library_View)}}</url>
<url>{{URL(:/PMS(owned)/media/providers::PlexConnect=Provider_View)}}</url>
</navigationItem>{{CUT($libraryview:CUT:=|Hide=CUT|Hide =)}}
<navigationItem id="SharedLibraries">
<title>{{TEXT(Shared Libraries)}}</title>
Expand Down
70 changes: 70 additions & 0 deletions assets/templates/Provider/List.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<atv>
<head>
<script src="{{URL(:/js/utils.js)}}" />
<script src="{{URL(:/js/sectionHoldSelect.js)}}" />
</head>

<body>
{{VAR(sections:NoKey:FALSE)}} <!--this sets the var to FALSE-->

<listWithPreview id="Library_List">
<header>
<simpleHeader>
<title>{{TEXT(Plex Library)}}</title>
</simpleHeader>
</header>
<menu>
<sections>

<!-- servers -->
<menuSection>
{{COPY(Server:@main/size::0=|1=COPY)}}

<header>
<horizontalDivider alignment="left">
<title>{{VAL(name)}}{{VAL(local::0= &lt;{{TEXT(remote)}}&gt;|0 =)}}</title>
</horizontalDivider>
</header>{{CUT(@main/size:CUT:0=CUT|1=CUT|1 =)}}

<items>

<!-- /library/sections -->
<oneLineMenuItem id="{{VAL(key)}}"
onPlay="atv.loadURL('{{URL(key:::PlexConnect={{EVAL('{{VAL(scanner)}}'.replace(' ', '_'))}})}}')"
onSelect="atv.loadURL('{{URL(key:::PlexConnect={{EVAL('{{VAL(scanner)}}'.replace(' ', '_'))}})}}')"
onHoldSelect="refreshSection('{{VAL(key)}}', '{{URL(refreshKey)}}')">
{{COPY(Directory)}}
{{VAR(sections:NoKey:TRUE)}} <!--within COPY this sets the var to TRUE-->
<label>{{VAL(title)}}</label>
<preview>
<link>{{URL(key::/recentlyAdded:stack=1&amp;X-Plex-Container-Start=0&amp;X-Plex-Container-Size=20&amp;PlexConnect=Main_SectionPreview-{{VAL(type)}})}}</link>{{CUT(type::a=|livetv=CUT|m=|photo=CUT|q=)}}
<link>{{URL(key::/recentlyAdded:X-Plex-Container-Start=0&amp;X-Plex-Container-Size=20&amp;PlexConnect=Main_SectionPreview-{{VAL(type)}})}}</link>{{CUT(type:CUT:a=CUT|photo=|q=CUT)}}
<link>{{URL(key::/all:type=1,4&amp;beginsAtyyltyy=now&amp;endsAtyygtyy=1s&amp;PlexConnect=Main_SectionPreview-{{VAL(type)}})}}</link>{{CUT(type:CUT:a=CUT|livetv=|m=CUT)}}
</preview>
</oneLineMenuItem>
<!-- search -->
<oneLineMenuItem id="{{VAL(searchKey)}}"
onPlay="atv.loadURL('{{URL(searchKey)}}')"
onSelect="atv.loadURL('{{URL(searchKey)}}')">
<label>{{TEXT(Search)}}</label>
<accessories>
<arrow/>
</accessories>
</oneLineMenuItem>

</items>
</menuSection>

</sections>
</menu>
</listWithPreview>{{CUT(#sections::FALSE=CUT|TRUE=)}} <!--CUT if no section added-->

<!--No Sections Available-->
<dialog id="com.sample.error-dialog">
{{CUT(#sections::FALSE=|TRUE=CUT)}}
<title>PlexConnect</title>
<description>{{TEXT(No Plex Library Sections Available)}}</description>
</dialog>

</body>
</atv>
3 changes: 3 additions & 0 deletions assets/templates/Provider/View.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<atv>
<redirect template="Provider/List.xml" />
</atv>

0 comments on commit 6ebd929

Please sign in to comment.