#!/usr/bin/env python
from plexapi.server import PlexServer
from datetime import datetime
import sqlite3
from yattag import Doc
from yattag import indent
import os, sys
import logging
import logging.handlers
class PseudoDailyScheduleController():
def __init__(self, server, token, clients, debugMode = False):
self.PLEX = PlexServer(server, token)
self.BASE_URL = server
self.TOKEN = token
self.PLEX_CLIENTS = clients
self.DEBUG = debugMode
self.my_logger = logging.getLogger('MyLogger')
self.my_logger.setLevel(logging.DEBUG)
self.handler = logging.handlers.SysLogHandler(address = '/dev/log')
self.my_logger.addHandler(self.handler)
'''
*
* Get the full image url (including plex token) from the local db.
* @param seriesTitle: case-unsensitive string of the series title
* @return string: full path of to the show image
*
'''
def get_show_photo(self, section, title):
backgroundImagePath = None
backgroundImgURL = ''
try:
backgroundImagePath = self.PLEX.library.section(section).get(title)
except:
return backgroundImgURL
if backgroundImagePath != None and isinstance(backgroundImagePath.art, str):
backgroundImgURL = self.BASE_URL+backgroundImagePath.art+"?X-Plex-Token="+self.TOKEN
return backgroundImgURL
def get_xml_from_daily_schedule(self, currentTime, bgImageURL, datalist):
now = datetime.now()
time = now.strftime("%B %d, %Y")
doc, tag, text, line = Doc(
).ttl()
doc.asis('')
with tag('schedule', currently_playing_bg_image=bgImageURL if bgImageURL != None else ''):
for row in datalist:
if str(row[11]) == "Commercials" and self.DEBUG == False:
continue
timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime == None:
with tag('time',
('data-key', str(row[12])),
('data-current', 'false'),
('data-type', str(row[11])),
('data-title', str(row[3])),
('data-start-time', str(row[8])),
):
text(row[8])
elif currentTime.hour == timeB.hour and currentTime.minute == timeB.minute:
with tag('time',
('data-key', str(row[12])),
('data-current', 'true'),
('data-type', str(row[11])),
('data-title', str(row[3])),
('data-start-time', str(row[8])),
):
text(row[8])
else:
with tag('time',
('data-key', str(row[12])),
('data-current', 'false'),
('data-type', str(row[11])),
('data-title', str(row[3])),
('data-start-time', str(row[8])),
):
text(row[8])
return indent(doc.getvalue())
'''
*
* Get the generated html for the .html file that is the schedule.
* ...This is used whenever a show starts or stops in order to add and remove various styles.
* @param currentTime: datetime object
* @param bgImageURL: str of the image used for the background
* @return string: the generated html content
*
'''
def get_html_from_daily_schedule(self, currentTime, bgImageURL, datalist):
now = datetime.now()
time = now.strftime("%B %d, %Y")
doc, tag, text, line = Doc(
).ttl()
doc.asis('')
with tag('html'):
with tag('head'):
with tag('title'):
text(time + " - Daily Pseudo Schedule")
doc.asis('')
doc.asis('')
if bgImageURL != None:
doc.asis('')
with tag('body'):
with tag('div', klass='container mt-3'):
with tag('div', klass='row make-white'):
with tag('div'):
with tag('div'):
line('h1', "Daily Pseudo Schedule", klass='col-12 pl-0')
with tag('div'):
line('h3', time, klass='col-12 pl-1')
with tag('table', klass='col-12 table table-bordered table-hover'):
with tag('thead', klass='table-info'):
with tag('tr'):
with tag('th'):
text('#')
with tag('th'):
text('Type')
with tag('th'):
text('Series')
with tag('th'):
text('Title')
with tag('th'):
text('Start Time')
numberIncrease = 0
for row in datalist:
if str(row[11]) == "Commercials" and self.DEBUG == False:
continue
numberIncrease += 1
with tag('tbody'):
timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime == None:
with tag('tr'):
with tag('th', scope='row'):
text(numberIncrease)
with tag('td'):
text(row[11])
with tag('td'):
text(row[6])
with tag('td'):
text(row[3])
with tag('td'):
text(row[8])
elif currentTime.hour == timeB.hour and currentTime.minute == timeB.minute:
with tag('tr', klass='bg-info'):
with tag('th', scope='row'):
text(numberIncrease)
with tag('td'):
text(row[11])
with tag('td'):
text(row[6])
with tag('td'):
text(row[3])
with tag('td'):
text(row[8])
else:
with tag('tr'):
with tag('th', scope='row'):
text(numberIncrease)
with tag('td'):
text(row[11])
with tag('td'):
text(row[6])
with tag('td'):
text(row[3])
with tag('td'):
text(row[8])
return indent(doc.getvalue())
'''
*
* Create 'schedules' dir & write the generated html to .html file.
* @param data: html string
* @return null
*
'''
def write_schedule_to_file(self, data):
now = datetime.now()
fileName = "index.html"
writepath = './schedules/'
if not os.path.exists(writepath):
os.makedirs(writepath)
if os.path.exists(writepath+fileName):
os.remove(writepath+fileName)
mode = 'a' if os.path.exists(writepath) else 'w'
with open(writepath+fileName, mode) as f:
f.write(data)
'''
*
* Create 'schedules' dir & write the generated xml to .xml file.
* @param data: xml string
* @return null
*
'''
def write_xml_to_file(self, data):
now = datetime.now()
fileName = "pseudo_schedule.xml"
writepath = './schedules/'
if not os.path.exists(writepath):
os.makedirs(writepath)
if os.path.exists(writepath+fileName):
os.remove(writepath+fileName)
mode = 'a' if os.path.exists(writepath) else 'w'
with open(writepath+fileName, mode) as f:
f.write(data)
'''
*
* Trigger "playMedia()" on the Python Plex API for specified media.
* @param mediaType: str: "TV Shows"
* @param mediaParentTitle: str: "Seinfeld"
* @param mediaTitle: str: "The Soup Nazi"
* @return null
*
'''
def play_media(self, mediaType, mediaParentTitle, mediaTitle):
if mediaType == "TV Shows":
mediaItems = self.PLEX.library.section(mediaType).get(mediaParentTitle).episodes()
for item in mediaItems:
# print(part.title)
if item.title == mediaTitle:
for client in self.PLEX_CLIENTS:
clientItem = self.PLEX.client(client)
clientItem.playMedia(item)
break
elif mediaType == "Movies":
movie = self.PLEX.library.section(mediaType).get(mediaTitle)
for client in self.PLEX_CLIENTS:
clientItem = self.PLEX.client(client)
clientItem.playMedia(movie)
elif mediaType == "Commercials":
movie = self.PLEX.library.section(mediaType).get(mediaTitle)
for client in self.PLEX_CLIENTS:
clientItem = self.PLEX.client(client)
clientItem.playMedia(movie)
else:
print("Not sure how to play {}".format(mediaType))
'''
*
* If tv_controller() does not find a "startTime" for scheduled media, search for an "endTime" match for now time.
* ...This is useful for clearing the generated html schedule when media ends and there is a gap before the next media.
* @param null
* @return null
*
'''
def check_for_end_time(self, datalist):
currentTime = datetime.now()
"""c.execute("SELECT * FROM daily_schedule")
datalist = list(c.fetchall())
"""
for row in datalist:
try:
endTime = datetime.strptime(row[9], '%Y-%m-%d %H:%M:%S.%f')
except ValueError:
endTime = datetime.strptime(row[9], '%Y-%m-%d %H:%M:%S')
if currentTime.hour == endTime.hour:
if currentTime.minute == endTime.minute:
if currentTime.second == endTime.second:
print("Ok end time found")
self.write_schedule_to_file(self.get_html_from_daily_schedule(None, None, datalist))
self.write_xml_to_file(self.get_xml_from_daily_schedule(None, None, datalist))
break
'''
*
* Check DB / current time. If that matches a scheduled shows startTime then trigger play via Plex API
* @param null
* @return null
*
'''
def tv_controller(self, datalist):
datalistLengthMonitor = 0;
currentTime = datetime.now()
"""c.execute("SELECT * FROM daily_schedule ORDER BY datetime(startTimeUnix) ASC")
datalist = list(c.fetchall())"""
self.my_logger.debug('TV Controller')
for row in datalist:
timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime.hour == timeB.hour:
if currentTime.minute == timeB.minute:
if currentTime.second == timeB.second:
print("Starting Media: " + row[3])
print(row)
self.play_media(row[11], row[6], row[3])
self.write_schedule_to_file(
self.get_html_from_daily_schedule(
timeB,
self.get_show_photo(
row[11],
row[6] if row[11] == "TV Shows" else row[3]
),
datalist
)
)
"""Generate / write XML to file
"""
self.write_xml_to_file(
self.get_xml_from_daily_schedule(
timeB,
self.get_show_photo(
row[11],
row[6] if row[11] == "TV Shows" else row[3]
),
datalist
)
)
self.my_logger.debug('Trying to play: ' + row[3])
break
datalistLengthMonitor += 1
if datalistLengthMonitor >= len(datalist):
self.check_for_end_time(datalist)
def make_xml_schedule(self, datalist):
print "+++++ ", "Writing XML / HTML to file."
self.write_schedule_to_file(self.get_html_from_daily_schedule(None, None, datalist))
self.write_xml_to_file(self.get_xml_from_daily_schedule(None, None, datalist))