Cleaning up code base, etc. getting ready for release.

This commit is contained in:
Justin Emter
2017-08-18 12:50:54 -07:00
parent 2205cf723b
commit daf8ced89b
6 changed files with 51 additions and 937 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,9 @@
"Movies" : ["Films"],
6) *Skip this feature for now* For Google Calendar integration add your "gkey" to the "plex_token.py" file
6) *Skip this feature for now*
For Google Calendar integration add your "gkey" to the "plex_token.py" file
...(https://docs.simplecalendar.io/find-google-calendar-id/):
gkey = "the key"
@@ -36,7 +38,7 @@
* List of plex clients to use (add multiple clients to control multiple TV's)
*
'''
plexClients = ['RasPlex']
plexClients = ['RasPlex2']
plexLibraries = {
"TV Shows" : ["TV Shows"],
@@ -68,18 +70,22 @@ useDailyOverlapCache = True
dailyUpdateTime = "12:00 AM"
"""Debug mode will give you more output in your terminal to help problem solve issues."""
debug_mode = True
"""---"""
useGoogleCalendar = False
"""When to delete / remake the pseudo-channel.log - right at midnight, (i.e. 'friday') """
rotateLog = "friday"
"""Debug mode will give you more output in your terminal to help problem solve issues."""
debug_mode = True
"""
##### Do not edit below this line.
##### Do not edit below this line---------------------------------------------------------------
Below is logic to grab your Plex 'token' & Plex 'baseurl'. If you are following along and have created a 'plex_token.py'
file as instructed, you do not need to edit below this line.

View File

@@ -24,7 +24,7 @@ by adding a '<time></time>' block within the part of the week you want it to be
below I have "Looney Tunes" scheduled to play "everyday" starting at "6:00 AM", whereas I have "Garfield &#38; Friends"
playing only on "weekday" mornings scheduled for after Looney Tunes starting at "8:00 AM". Also notice that
"Garfield &#38; Friends" below is actually written as, "Garfield &#38; Friends". This is especially important
to those new to editing XML. In XML, "UTF-8", you are forbidden from using certain characters like the "&#38;"
to those new to editing XML. In XML, "UTF-8", you are forbidden from using certain characters like the and
character. It is important to convert your titles to XML friendly text (this is also important for non-english characters).
You can find all of this information by googling "xml ascii character conversion".
@@ -36,7 +36,7 @@ to either "series" or "movie". The attribute "strict-time" can either be "true"
whether or not the particular "<time>" block will be scheduled for the exact time you specify or if it will
shift around to fill up gaps. This is useful as sometimes episodes are as short as 5 minutes (cartoons) while
other episodes that are normally ~25 minutes are an hour or so long. Setting "strict-time" to "false" will
tell the app to movie that time block closer to the previous episode. The corrisponding, "time-shift" attribute
tell the app to shift that time block closer to the previous episode. The corresponding, "time-shift" attribute
tells the app how to shift the item. Its value can be "1" or more and will help the scheduler determine when to schedule the
shifting time according to that value. So for instance, if you'd like no gaps between your content, then you want
to set "strict-time='false'" and "time-shift='1'". However if you want your content to shift but would rather
@@ -48,7 +48,7 @@ nearest multiple of "5". You could use "15" or "30" too for even prettier times.
Well, since the app is supposed to work like a real TV Channel, you aren't supposed to have that kind of
control. If you want to watch "Billy Madison" then why not just turn on your Plex TV app and play it? Instead
here you want to always use "random" tor the "title=" value. But let's say you have a ton of Adam Sandler
here you want to always use "random" tor the "title=" value of movie content. But let's say you have a ton of Adam Sandler
movies and want to schedule a "random" Adam Sandler movie on Saturday afternoon? That makes more sense, that way
you aren't playing the same movie every Saturday afternoon! For movies specifically, you have a new
attribute called "xtra". There you can add various parameters to narrow in on the random movie type you
@@ -63,12 +63,11 @@ The available "xtra" paramters are as follows (http://python-plexapi.readthedocs
* duplicate: Display or hide duplicate items (True, False). [movie]
* actor: List of actors to search ([actor_or_id, ...]). [movie]
* collection: List of collections to search within ([collection_or_id, ...]). [all]
* contentRating: List of content ratings to search within ([rating_or_key, ...]). [movie,tv]
* contentRating: List of content ratings to search within ([rating_or_key, ...]). [movie]
* country: List of countries to search within ([country_or_key, ...]). [movie,music]
* decade: List of decades to search within ([yyy0, ...]). [movie]
* director: List of directors to search ([director_or_id, ...]). [movie]
* genre: List Genres to search within ([genere_or_id, ...]). [all]
* network: List of TV networks to search within ([resolution_or_key, ...]). [tv]
* resolution: List of video resolutions to search within ([resolution_or_key, ...]). [movie]
* studio: List of studios to search within ([studio_or_key, ...]). [music]
* year: List of years to search within ([yyyy, ...]). [all]
@@ -83,7 +82,7 @@ or whatever you can come up with. All you have to do is set the commercial flag
file to tell the app to use "commercial injection" and make sure you have a "Commercials" library in your
plex media library. In that library, fill it with as many commercials or short videos as you can. The more
the better! I have close to a thousand commercials in mine - this helps the app fill up the gaps with a
wide variety of video content of different durations. (hint: use a tool like 'youtube-dl' to download full
wide variety of video content of varied durations. (hint: use a tool like 'youtube-dl' to download full
playlists from yourtube. You can fill up your "Commercials" library quick). Once you have your commercials library
setup, make sure to run, "python PseudoChannel.py -u" once more to update your local db with your new commercials
library. Commercials will now be "injected" to fill up gaps upon the next days schedule (or you can manually
@@ -101,7 +100,8 @@ using the XML ascii character "&#38;". Well you cannot do that. I usually like t
open in a tab while making my XML. That way for each "series" title I can double check the library to make sure I
am using the series title exactly as Plex is.
Ok, that is it. If you have questions feel free to e-mail me at justin@pseudochannel.tv. Have fun!
Ok, that is it. If you have questions feel free to e-mail me at justin@pseudochannel.tv or open an 'issue' on the
github repository. Have fun!
Cheers!

View File

@@ -16,147 +16,86 @@ class PseudoChannelCommercial():
def __init__(self, commercials, commercialPadding):
self.commercials = commercials
self.COMMERCIAL_PADDING_IN_SECONDS = commercialPadding
def get_commercials_to_inject(self):
self.go()
return None
def get_random_commercial(self):
random_commercial = random.choice(self.commercials)
random_commercial_dur_seconds = (int(random_commercial[4])/1000)%60
while random_commercial_dur_seconds < self.MIN_DURATION_FOR_COMMERCIAL:
random_commercial = random.choice(self.commercials)
random_commercial_dur_seconds = (int(random_commercial[4])/1000)%60
return random_commercial
def go(self):
shuffled_commercial_list = copy.deepcopy(self.commercials)
random.shuffle(self.commercials, random.random)
#print shuffled_commercial_list
prev_item = None
for entry in self.daily_schedule:
"""First Episode"""
if prev_item == None:
prev_item = entry
else:
prev_item_end_time = datetime.datetime.strptime(prev_item[9], '%Y-%m-%d %H:%M:%S.%f')
curr_item_start_time = datetime.datetime.strptime(entry[8], '%I:%M:%S %p')
time_diff = (curr_item_start_time - prev_item_end_time)
days, hours, minutes = time_diff.days, time_diff.seconds // 3600, time_diff.seconds // 60 % 60
count = 0
commercial_list = []
commercial_dur_sum = 0
while int(time_diff.total_seconds()) >= commercial_dur_sum and count < len(self.commercials):
random_commercial = self.get_random_commercial()
commercial_list.append(random_commercial)
commercial_dur_sum += int(random_commercial[4])
print commercial_list
prev_item = entry
def timedelta_milliseconds(self, td):
return td.days*86400000 + td.seconds*1000 + td.microseconds/1000
def pad_the_commercial_dur(self, commercial):
commercial_as_list = list(commercial)
commercial_as_list[4] = int(commercial_as_list[4]) + (self.COMMERCIAL_PADDING_IN_SECONDS * 1000)
commercial = tuple(commercial_as_list)
return commercial
def get_commercials_to_place_between_media(self, last_ep, now_ep):
#print last_ep.end_time, now_ep.start_time
prev_item_end_time = datetime.strptime(last_ep.end_time.strftime('%Y-%m-%d %H:%M:%S.%f'), '%Y-%m-%d %H:%M:%S.%f')
curr_item_start_time = datetime.strptime(now_ep.start_time, '%I:%M:%S %p')
time_diff = (curr_item_start_time - prev_item_end_time)
count = 0
commercial_list = []
commercial_dur_sum = 0
time_diff_milli = self.timedelta_milliseconds(time_diff)
last_commercial = None
time_watch = prev_item_end_time
new_commercial_start_time = prev_item_end_time
#print "here", time_diff.seconds
while curr_item_start_time > new_commercial_start_time and (count) < len(self.commercials)*100:
random_commercial_without_pad = self.get_random_commercial()
"""
Padding the duration of commercials as per user specified padding.
"""
random_commercial = self.pad_the_commercial_dur(random_commercial_without_pad)
#new_commercial_seconds = (int(random_commercial[4])/1000)%60
new_commercial_milli = int(random_commercial[4])
if last_commercial != None:
#print last_commercial[3]
new_commercial_start_time = last_commercial.end_time
new_commercial_end_time = new_commercial_start_time + \
timedelta(milliseconds=int(new_commercial_milli))
else:
new_commercial_start_time = prev_item_end_time
new_commercial_end_time = new_commercial_start_time + \
timedelta(milliseconds=int(new_commercial_milli))
commercial_dur_sum += new_commercial_milli
formatted_time_for_new_commercial = new_commercial_start_time.strftime('%I:%M:%S %p')
new_commercial = Commercial(
"Commercials",
random_commercial[3],
@@ -169,15 +108,8 @@ class PseudoChannelCommercial():
"0", # overlap_max
"", # plex_media_id
)
last_commercial = new_commercial
if new_commercial_end_time > curr_item_start_time:
break
commercial_list.append(new_commercial)
#print "here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
return commercial_list

View File

@@ -9,83 +9,61 @@ class PseudoChannelDatabase():
def __init__(self, db):
self.db = db
self.conn = sqlite3.connect(self.db, check_same_thread=False)
self.cursor = self.conn.cursor()
"""Database functions.
Utilities, etc.
"""
def create_tables(self):
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'movies(id INTEGER PRIMARY KEY AUTOINCREMENT, '
'unix INTEGER, mediaID INTEGER, title TEXT, duration INTEGER, '
'lastPlayedDate TEXT, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'videos(id INTEGER PRIMARY KEY AUTOINCREMENT, '
'unix INTEGER, mediaID INTEGER, title TEXT, duration INTEGER, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'music(id INTEGER PRIMARY KEY AUTOINCREMENT, '
'unix INTEGER, mediaID INTEGER, title TEXT, duration INTEGER, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'shows(id INTEGER PRIMARY KEY AUTOINCREMENT, '
'unix INTEGER, mediaID INTEGER, title TEXT, duration INTEGER, '
'lastEpisodeTitle TEXT, fullImageURL TEXT, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'episodes(id INTEGER PRIMARY KEY AUTOINCREMENT, '
'unix INTEGER, mediaID INTEGER, title TEXT, duration INTEGER, '
'episodeNumber INTEGER, seasonNumber INTEGER, showTitle TEXT, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'commercials(id INTEGER PRIMARY KEY AUTOINCREMENT, unix INTEGER, '
'mediaID INTEGER, title TEXT, duration INTEGER, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'schedule(id INTEGER PRIMARY KEY AUTOINCREMENT, unix INTEGER, '
'mediaID INTEGER, title TEXT, duration INTEGER, startTime INTEGER, '
'endTime INTEGER, dayOfWeek TEXT, startTimeUnix INTEGER, section TEXT, '
'strictTime TEXT, timeShift TEXT, overlapMax TEXT, xtra TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'daily_schedule(id INTEGER PRIMARY KEY AUTOINCREMENT, unix INTEGER, '
'mediaID INTEGER, title TEXT, episodeNumber INTEGER, seasonNumber INTEGER, '
'showTitle TEXT, duration INTEGER, startTime INTEGER, endTime INTEGER, '
'dayOfWeek TEXT, sectionType TEXT, plexMediaID TEXT)')
self.cursor.execute('CREATE TABLE IF NOT EXISTS '
'app_settings(id INTEGER PRIMARY KEY AUTOINCREMENT, version TEXT)')
#index
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_episode_title ON episodes (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_movie_title ON movies (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_shows_title ON shows (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_video_title ON videos (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_music_title ON music (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_commercial_title ON commercials (title);')
self.cursor.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_settings_version ON app_settings (version);')
"""Setting Basic Settings
"""
try:
self.cursor.execute("INSERT OR REPLACE INTO app_settings "
"(version) VALUES (?)",
("0.1",))
self.conn.commit()
# Catch the exception
except Exception as e:
@@ -104,9 +82,7 @@ class PseudoChannelDatabase():
def drop_daily_schedule_table(self):
sql = "DROP TABLE IF EXISTS daily_schedule"
self.cursor.execute(sql)
self.conn.commit()
def create_daily_schedule_table(self):
@@ -116,45 +92,36 @@ class PseudoChannelDatabase():
'mediaID INTEGER, title TEXT, episodeNumber INTEGER, seasonNumber INTEGER, '
'showTitle TEXT, duration INTEGER, startTime INTEGER, endTime INTEGER, '
'dayOfWeek TEXT, sectionType TEXT, plexMediaID TEXT)')
self.conn.commit()
def remove_all_scheduled_items(self):
sql = "DELETE FROM schedule WHERE id > -1"
self.cursor.execute(sql)
self.conn.commit()
def remove_all_daily_scheduled_items(self):
sql = "DELETE FROM daily_schedule"
self.cursor.execute(sql)
self.conn.commit()
def clear_shows_table(self):
sql = "DELETE FROM shows"
self.cursor.execute(sql)
self.conn.commit()
"""Database functions.
Setters, etc.
"""
def add_movies_to_db(self, mediaID, title, duration, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("REPLACE INTO movies "
"(unix, mediaID, title, duration, plexMediaID) VALUES (?, ?, ?, ?, ?)",
(unix, mediaID, title, duration, plexMediaID))
self.conn.commit()
# Catch the exception
except Exception as e:
@@ -163,6 +130,7 @@ class PseudoChannelDatabase():
raise e
def add_videos_to_db(self, mediaID, title, duration, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("REPLACE INTO videos "
@@ -177,6 +145,7 @@ class PseudoChannelDatabase():
raise e
def add_shows_to_db(self, mediaID, title, duration, lastEpisodeTitle, fullImageURL, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("INSERT OR IGNORE INTO shows "
@@ -190,6 +159,7 @@ class PseudoChannelDatabase():
raise e
def add_episodes_to_db(self, mediaID, title, duration, episodeNumber, seasonNumber, showTitle, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("REPLACE INTO episodes "
@@ -203,6 +173,7 @@ class PseudoChannelDatabase():
raise e
def add_commercials_to_db(self, mediaID, title, duration, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("REPLACE INTO commercials "
@@ -258,9 +229,7 @@ class PseudoChannelDatabase():
):
unix = int(time.time())
try:
self.cursor.execute("INSERT OR REPLACE INTO daily_schedule "
"(unix, mediaID, title, episodeNumber, seasonNumber, "
"showTitle, duration, startTime, endTime, dayOfWeek, sectionType, plexMediaID) "
@@ -279,16 +248,11 @@ class PseudoChannelDatabase():
sectionType,
plexMediaID
))
self.conn.commit()
# Catch the exception
except Exception as e:
# Roll back any change if something goes wrong
self.conn.rollback()
raise e
def add_media_to_daily_schedule(self, media):
@@ -297,7 +261,6 @@ class PseudoChannelDatabase():
print str("#### Adding media to db: {} {}".format(media.title, media.start_time)).encode('UTF-8')
except:
print "----- Not outputting media info due to ascii code issues."
self.add_daily_schedule_to_db(
0,
media.title,
@@ -313,6 +276,7 @@ class PseudoChannelDatabase():
)
def import_shows_table_by_row(self, mediaID, title, duration, lastEpisodeTitle, fullImageURL, plexMediaID):
unix = int(time.time())
try:
self.cursor.execute("REPLACE INTO shows "
@@ -326,102 +290,79 @@ class PseudoChannelDatabase():
raise e
"""Database functions.
Getters, etc.
"""
def get_shows_table(self):
sql = "SELECT * FROM shows"
self.cursor.execute(sql)
return self.cursor.fetchall()
def get_media(self, title, mediaType):
media = mediaType
sql = "SELECT * FROM "+media+" WHERE (title LIKE ?) COLLATE NOCASE"
self.cursor.execute(sql, ("%"+title+"%", ))
media_item = self.cursor.fetchone()
return media_item
def get_schedule(self):
self.cursor.execute("SELECT * FROM schedule ORDER BY datetime(startTimeUnix) ASC")
datalist = list(self.cursor.fetchall())
return datalist
def get_daily_schedule(self):
print "##### Getting Daily Schedule from DB."
self.cursor.execute("SELECT * FROM daily_schedule ORDER BY datetime(startTime) ASC")
datalist = list(self.cursor.fetchall())
print "+++++ Done."
return datalist
def get_movie(self, title):
media = "movies"
return self.get_media(title, media)
def get_shows(self, title):
media = "shows"
return self.get_media(title, media)
def get_music(self, title):
media = "music"
return self.get_media(title, media)
def get_video(self, title):
media = "videos"
return self.get_media(title, media)
def get_episodes(self, title):
media = "episodes"
return self.get_media(title, media)
def get_commercials(self):
self.cursor.execute("SELECT * FROM commercials ORDER BY duration ASC")
datalist = list(self.cursor.fetchall())
return datalist
def update_shows_table_with_last_episode(self, showTitle, lastEpisodeTitle):
sql1 = "UPDATE shows SET lastEpisodeTitle = ? WHERE title LIKE ? COLLATE NOCASE"
self.cursor.execute(sql1, (lastEpisodeTitle, showTitle, ))
self.conn.commit()
def get_first_episode(self, tvshow):
sql = ("SELECT id, unix, mediaID, title, duration, MIN(episodeNumber), MIN(seasonNumber), "
"showTitle FROM episodes WHERE ( showTitle LIKE ?) COLLATE NOCASE")
self.cursor.execute(sql, (tvshow, ))
first_episode = self.cursor.fetchone()
return first_episode
'''
@@ -432,32 +373,24 @@ class PseudoChannelDatabase():
def get_episode_id(self, episodeTitle):
sql = "SELECT id FROM episodes WHERE ( title LIKE ?) COLLATE NOCASE"
self.cursor.execute(sql, (episodeTitle, ))
episode_id = self.cursor.fetchone()
return episode_id
def get_random_episode(self):
sql = "SELECT * FROM episodes WHERE id IN (SELECT id FROM episodes ORDER BY RANDOM() LIMIT 1)"
self.cursor.execute(sql)
return self.cursor.fetchone()
def get_random_movie(self):
sql = "SELECT * FROM movies WHERE id IN (SELECT id FROM movies ORDER BY RANDOM() LIMIT 1)"
self.cursor.execute(sql)
return self.cursor.fetchone()
def get_next_episode(self, series):
#print(series)
'''
*
* As a way of storing a "queue", I am storing the *next episode title in the "shows" table so I can
@@ -465,7 +398,6 @@ class PseudoChannelDatabase():
*
'''
self.cursor.execute("SELECT lastEpisodeTitle FROM shows WHERE title LIKE ? COLLATE NOCASE", (series, ))
last_title_list = self.cursor.fetchone()
'''
*
@@ -480,17 +412,13 @@ class PseudoChannelDatabase():
*
'''
first_episode = self.get_first_episode(series)
first_episode_title = first_episode[3]
#print(first_episode_title)
'''
*
* Add this episdoe title to the "shows" table for the queue functionality to work
*
'''
self.update_shows_table_with_last_episode(series, first_episode_title)
return first_episode
elif last_title_list:
@@ -499,10 +427,6 @@ class PseudoChannelDatabase():
* The last episode stored in the "shows" table was not empty... get the next episode in the series
*
'''
#print("First episode already set in shows, advancing episodes forward")
#print(str(self.get_episode_id(last_title_list[0])))
"""
*
* If this isn't a first run, then grabbing the next episode by incrementing id
@@ -510,7 +434,6 @@ class PseudoChannelDatabase():
"""
sql = ("SELECT * FROM episodes WHERE ( id > "+str(self.get_episode_id(last_title_list[0])[0])+
" AND showTitle LIKE ? ) ORDER BY seasonNumber LIMIT 1 COLLATE NOCASE")
self.cursor.execute(sql, (series, ))
'''
*
@@ -518,38 +441,23 @@ class PseudoChannelDatabase():
*
'''
next_episode = self.cursor.fetchone()
if next_episode != None:
#print(next_episode[3])
self.update_shows_table_with_last_episode(series, next_episode[3])
return next_episode
else:
print("Not grabbing next episode restarting series, series must be over. Restarting from episode 1.")
print("+++++ Not grabbing next episode restarting series, series must be over. Restarting from episode 1.")
first_episode = self.get_first_episode(series)
self.update_shows_table_with_last_episode(series, first_episode[3])
return first_episode
def get_commercial(self, title):
media = "commercials"
sql = "SELECT * FROM "+media+" WHERE (title LIKE ?) COLLATE NOCASE"
self.cursor.execute(sql, (title, ))
datalist = list(self.cursor.fetchone())
if datalist > 0:
print(datalist)
return datalist
else:
return None
return None

View File

@@ -1,18 +1,15 @@
#!/usr/bin/env python
from plexapi.server import PlexServer
from datetime import datetime
import sqlite3
import thread,SocketServer,SimpleHTTPServer
from yattag import Doc
from yattag import indent
import os, sys
import socket
import logging
import logging.handlers
from datetime import datetime
import sqlite3
import thread,SocketServer,SimpleHTTPServer
from plexapi.server import PlexServer
from yattag import Doc
from yattag import indent
class PseudoDailyScheduleController():
@@ -26,32 +23,19 @@ class PseudoDailyScheduleController():
):
self.PLEX = PlexServer(server, token)
self.BASE_URL = server
self.TOKEN = token
self.PLEX_CLIENTS = clients
self.CONTROLLER_SERVER_PATH = controllerServerPath
self.CONTROLLER_SERVER_PORT = controllerServerPort if controllerServerPort != '' else '80'
self.DEBUG = debugMode
self.webserverStarted = False
try:
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)
except:
pass
'''
@@ -64,33 +48,22 @@ class PseudoDailyScheduleController():
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 start_server(self):
if self.webserverStarted == False and self.CONTROLLER_SERVER_PATH != '':
"""Changing dir to the schedules dir."""
web_dir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'schedules'))
os.chdir(web_dir)
PORT = int(self.CONTROLLER_SERVER_PORT)
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def log_message(self, format, *args):
@@ -104,49 +77,34 @@ class PseudoDailyScheduleController():
class ReusableTCPServer(SocketServer.TCPServer): allow_reuse_address=True
# specify the httpd service on 0.0.0.0 (all interfaces) on port 80
httpd = ReusableTCPServer(("0.0.0.0", PORT),MyHandler)
# thread this mofo
thread.start_new_thread(httpd.serve_forever,())
# handle keyboard interrupts
except KeyboardInterrupt:
core.print_info("Exiting the SET web server...")
httpd.socket.close()
except socket.error, exc:
print "Caught exception socket.error : %s" % exc
# handle the rest
#except Exception:
# print "[*] Exiting the SET web server...\n"
# httpd.socket.close()
self.webserverStarted = True
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('<?xml version="1.0" encoding="UTF-8"?>')
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'),
@@ -154,11 +112,8 @@ class PseudoDailyScheduleController():
('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'),
@@ -166,11 +121,8 @@ class PseudoDailyScheduleController():
('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'),
@@ -178,12 +130,9 @@ class PseudoDailyScheduleController():
('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.
@@ -196,27 +145,18 @@ class PseudoDailyScheduleController():
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('<!DOCTYPE html>')
with tag('html'):
with tag('head'):
with tag('title'):
text(time + " - Daily Pseudo Schedule")
doc.asis('<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">')
doc.asis('<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">')
doc.asis('<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>')
doc.asis("""
<script>
$(function(){
@@ -271,28 +211,17 @@ class PseudoDailyScheduleController():
});
</script>
""")
if bgImageURL != None:
doc.asis('<style>body{ background:transparent!important; } html { background: url('+bgImageURL+') no-repeat center center fixed; -webkit-background-size: cover;-moz-background-size: cover;-o-background-size: cover;background-size: cover;}.make-white { padding: 24px; background:rgba(255,255,255, 0.9); }</style>')
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'):
@@ -305,23 +234,14 @@ class PseudoDailyScheduleController():
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)
@@ -333,11 +253,8 @@ class PseudoDailyScheduleController():
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'):
@@ -348,9 +265,7 @@ class PseudoDailyScheduleController():
text(row[3])
with tag('td'):
text(row[8])
else:
with tag('tr'):
with tag('th', scope='row'):
text(numberIncrease)
@@ -362,8 +277,6 @@ class PseudoDailyScheduleController():
text(row[3])
with tag('td'):
text(row[8])
return indent(doc.getvalue())
'''
@@ -376,25 +289,15 @@ class PseudoDailyScheduleController():
def write_schedule_to_file(self, data):
now = datetime.now()
fileName = "index.html"
writepath = './' if os.path.basename(os.getcwd()) == "schedules" else "./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)
self.start_server()
'''
@@ -407,26 +310,16 @@ class PseudoDailyScheduleController():
def write_xml_to_file(self, data):
now = datetime.now()
fileName = "pseudo_schedule.xml"
writepath = './' if os.path.basename(os.getcwd()) == "schedules" else "./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)
'''
*
* Write 0 or 1 to file for the ajax in the schedule.html to know when to refresh
@@ -437,44 +330,27 @@ class PseudoDailyScheduleController():
def write_refresh_bool_to_file(self):
fileName = "pseudo_refresh.txt"
writepath = './' if os.path.basename(os.getcwd()) == "schedules" else "./schedules/"
first_line = ''
if not os.path.exists(writepath):
os.makedirs(writepath)
if not os.path.exists(writepath+fileName):
file(writepath+fileName, 'w').close()
mode = 'r+'
with open(writepath+fileName, mode) as f:
f.seek(0)
first_line = f.read()
if self.DEBUG:
print "+++++ Html refresh flag: {}".format(first_line)
if first_line == '' or first_line == "0":
f.seek(0)
f.truncate()
f.write("1")
else:
f.seek(0)
f.truncate()
f.write("0")
#f.close()
'''
*
* Trigger "playMedia()" on the Python Plex API for specified media.
@@ -486,61 +362,32 @@ class PseudoDailyScheduleController():
'''
def play_media(self, mediaType, mediaParentTitle, mediaTitle, offset):
try:
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, offset=offset)
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, offset=offset)
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, offset=offset)
else:
print("##### Not sure how to play {}".format(mediaType))
print "+++++ Done."
except Exception as e:
print e.__doc__
print e.message
print "##### There was an error trying to play the media."
pass
'''
@@ -554,49 +401,32 @@ class PseudoDailyScheduleController():
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:
if self.DEBUG:
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))
self.write_refresh_bool_to_file()
break
def play(self, row, datalist, offset=0):
print str("##### Starting Media: '{}'".format(row[3])).encode('UTF-8')
print str("##### Media Offset: '{}' seconds.".format(int(offset / 1000))).encode('UTF-8')
if self.DEBUG:
print str(row).encode('UTF-8')
timeB = datetime.strptime(row[8], '%I:%M:%S %p')
self.play_media(row[11], row[6], row[3], offset)
self.write_schedule_to_file(
self.get_html_from_daily_schedule(
timeB,
@@ -607,9 +437,7 @@ class PseudoDailyScheduleController():
datalist
)
)
self.write_refresh_bool_to_file()
"""Generate / write XML to file
"""
self.write_xml_to_file(
@@ -622,15 +450,11 @@ class PseudoDailyScheduleController():
datalist
)
)
try:
self.my_logger.debug('Trying to play: ' + row[3])
except:
pass
'''
*
* Check DB / current time. If that matches a scheduled shows startTime then trigger play via Plex API
@@ -641,36 +465,21 @@ class PseudoDailyScheduleController():
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())"""
try:
self.my_logger.debug('TV Controller')
except:
pass
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,
@@ -681,9 +490,7 @@ class PseudoDailyScheduleController():
datalist
)
)
self.write_refresh_bool_to_file()
"""Generate / write XML to file
"""
self.write_xml_to_file(
@@ -696,26 +503,18 @@ class PseudoDailyScheduleController():
datalist
)
)
try:
self.my_logger.debug('Trying to play: ' + row[3])
except:
pass
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_refresh_bool_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))