diff --git a/PseudoChannel.py b/PseudoChannel.py index 25a35cf..e649fb5 100644 --- a/PseudoChannel.py +++ b/PseudoChannel.py @@ -1,18 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from src import PseudoChannelDatabase -from src import Movie -from src import Commercial -from src import Episode -from src import Music -from src import Video -from src import PseudoDailyScheduleController -from src import GoogleCalendar -from src import PseudoChannelCommercial - -from plexapi.server import PlexServer - import sys import datetime from datetime import time @@ -28,11 +16,18 @@ import json from pprint import pprint import random import re - +from plexapi.server import PlexServer import schedule - from time import sleep - +from src import PseudoChannelDatabase +from src import Movie +from src import Commercial +from src import Episode +from src import Music +from src import Video +from src import PseudoDailyScheduleController +from src import GoogleCalendar +from src import PseudoChannelCommercial import pseudo_config as config reload(sys) @@ -43,32 +38,21 @@ class PseudoChannel(): PLEX = PlexServer(config.baseurl, config.token) MEDIA = [] GKEY = config.gkey - USING_GOOGLE_CALENDAR = config.useGoogleCalendar - USING_COMMERCIAL_INJECTION = config.useCommercialInjection - DAILY_UPDATE_TIME = config.dailyUpdateTime - APP_TIME_FORMAT_STR = '%I:%M:%S %p' - COMMERCIAL_PADDING_IN_SECONDS = config.commercialPadding - CONTROLLER_SERVER_PATH = config.controllerServerPath CONTROLLER_SERVER_PORT = config.controllerServerPort - USE_OVERRIDE_CACHE = config.useDailyOverlapCache - DEBUG = config.debug_mode - ROTATE_LOG = config.rotateLog def __init__(self): logging.basicConfig(filename="pseudo-channel.log", level=logging.INFO) - self.db = PseudoChannelDatabase("pseudo-channel.db") - self.controller = PseudoDailyScheduleController( config.baseurl, config.token, @@ -77,17 +61,11 @@ class PseudoChannel(): self.CONTROLLER_SERVER_PORT, self.DEBUG ) - """Database functions. - update_db(): Grab the media from the Plex DB and store it in the local pseudo-channel.db. - drop_db(): Drop the local database. Fresh start. - update_schedule(): Update schedule with user defined times. - drop_schedule(): Drop the user defined schedule table. - generate_daily_schedule(): Generates daily schedule based on the "schedule" table. """ @@ -117,27 +95,16 @@ class PseudoChannel(): def update_db(self): print("#### Updating Local Database") - self.db.create_tables() - libs_dict = config.plexLibraries - sections = self.PLEX.library.sections() - for section in sections: - for correct_lib_name, user_lib_name in libs_dict.items(): - if section.title.lower() in [x.lower() for x in user_lib_name]: - if correct_lib_name == "Movies": - sectionMedia = self.PLEX.library.section(section.title).all() - for i, media in enumerate(sectionMedia): - self.db.add_movies_to_db(1, media.title, media.duration, media.key) - self.print_progress( i + 1, len(sectionMedia), @@ -145,24 +112,14 @@ class PseudoChannel(): suffix = 'Complete', bar_length = 40 ) - - elif correct_lib_name == "TV Shows": - sectionMedia = self.PLEX.library.section(section.title).all() - for i, media in enumerate(sectionMedia): - backgroundImagePath = self.PLEX.library.section(section.title).get(media.title) - backgroundImgURL = '' - if isinstance(backgroundImagePath.art, str): - backgroundImgURL = config.baseurl+backgroundImagePath.art+"?X-Plex-Token="+config.token - self.db.add_shows_to_db(2, media.title, media.duration, '', backgroundImgURL, media.key) - self.print_progress( i + 1, len(sectionMedia), @@ -170,16 +127,11 @@ class PseudoChannel(): suffix = 'Complete', bar_length = 40 ) - #add all episodes of each tv show to episodes table episodes = self.PLEX.library.section(section.title).get(media.title).episodes() - for episode in episodes: - duration = episode.duration - if duration: - self.db.add_episodes_to_db( 4, episode.title, @@ -189,9 +141,7 @@ class PseudoChannel(): media.title, episode.key ) - else: - self.db.add_episodes_to_db( 4, episode.title, @@ -201,17 +151,11 @@ class PseudoChannel(): media.title, episode.key ) - elif correct_lib_name == "Commercials": - sectionMedia = self.PLEX.library.section(section.title).all() - media_length = len(sectionMedia) - for i, media in enumerate(sectionMedia): - self.db.add_commercials_to_db(3, media.title, media.duration, media.key) - self.print_progress( i + 1, media_length, @@ -223,13 +167,9 @@ class PseudoChannel(): def update_schedule_from_google_calendar(self): self.gcal = GoogleCalendar(self.GKEY) - events = self.gcal.get_entries() - self.db.create_tables() - self.db.remove_all_scheduled_items() - scheduled_days_list = [ "mondays", "tuesdays", @@ -242,14 +182,12 @@ class PseudoChannel(): "weekends", "everyday" ] - section_dict = { "TV Shows" : ["series", "shows", "tv", "episodes", "tv shows", "show"], "Movies" : ["movie", "movies", "films", "film"], "Videos" : ["video", "videos", "vid"], "Music" : ["music", "songs", "song", "tune", "tunes"] } - weekday_dict = { "0" : ["mondays", "weekdays", "everyday"], "1" : ["tuesdays", "weekdays", "everyday"], @@ -259,56 +197,32 @@ class PseudoChannel(): "5" : ["saturdays", "weekends", "everyday"], "6" : ["sundays", "weekends", "everyday"], } - for event in events: - titlelist = [x.strip() for x in event['summary'].split(',')] - start = event['start'].get('dateTime', event['start'].get('date')) - s = datetime.datetime.strptime(start,"%Y-%m-%dT%H:%M:%S-07:00") - weekno = s.weekday() - for key, value in section_dict.items(): - if str(titlelist[0]).lower() == key or str(titlelist[0]).lower() in value: - print "Adding {} to schedule.".format(titlelist[1]) - title = titlelist[1] - # s.strftime('%I:%M'), event["summary"] natural_start_time = self.translate_time(s.strftime(self.APP_TIME_FORMAT_STR)) - natural_end_time = 0 - section = key - for dnum, daylist in weekday_dict.items(): - #print int(weekno), int(dnum) - if int(weekno) == int(dnum): - day_of_week = daylist[0] - strict_time = titlelist[2] if len(titlelist) > 2 else "true" - #strict_time = "true" - time_shift = "5" - overlap_max = "" - print natural_start_time - start_time_unix = datetime.datetime.strptime( self.translate_time(natural_start_time), '%I:%M:%S %p').strftime('%Y-%m-%d %H:%M:%S') - #print "Adding: ", time.tag, section, time.text, time.attrib['title'] - self.db.add_schedule_to_db( 0, # mediaID title, # title @@ -329,11 +243,8 @@ class PseudoChannel(): abspath = os.path.abspath(__file__) dname = os.path.dirname(abspath) os.chdir(dname) - self.db.create_tables() - self.db.remove_all_scheduled_items() - scheduled_days_list = [ "mondays", "tuesdays", @@ -346,52 +257,31 @@ class PseudoChannel(): "weekends", "everyday" ] - section_dict = { "TV Shows" : ["series", "shows", "tv", "episodes", "tv shows", "show"], "Movies" : ["movie", "movies", "films", "film"], "Videos" : ["video", "videos", "vid"], "Music" : ["music", "songs", "song", "tune", "tunes"] } - tree = ET.parse('pseudo_schedule.xml') - root = tree.getroot() - for child in root: - if child.tag in scheduled_days_list: - for time in child.iter("time"): - for key, value in section_dict.items(): - if time.attrib['type'] == key or time.attrib['type'] in value: - title = time.attrib['title'] if 'title' in time.attrib else '' - natural_start_time = self.translate_time(time.text) - natural_end_time = 0 - section = key - day_of_week = child.tag - strict_time = time.attrib['strict-time'] if 'strict-time' in time.attrib else 'false' - time_shift = time.attrib['time-shift'] if 'time-shift' in time.attrib else '1' - overlap_max = time.attrib['overlap-max'] if 'overlap-max' in time.attrib else '' - seriesOffset = time.attrib['series-offset'] if 'series-offset' in time.attrib else '' - xtra = time.attrib['xtra'] if 'xtra' in time.attrib else '' - start_time_unix = self.translate_time(time.text) - print "Adding: ", time.tag, section, time.text, time.attrib['title'] - self.db.add_schedule_to_db( 0, # mediaID title, # title @@ -419,53 +309,20 @@ class PseudoChannel(): self.db.remove_all_scheduled_items() - - - """App functions. - - generate_daily_schedule(): Generate the daily_schedule table. - """ - - ''' - * - * Using datetime to figure out when the media item will end based on the scheduled start time or the offset - * generated by the previous media item. - - * Returns time - * - ''' - ''' - * - * Returns time difference in minutes - * - ''' - def translate_time(self, timestr): try: - return datetime.datetime.strptime(timestr, '%I:%M %p').strftime(self.APP_TIME_FORMAT_STR) - except ValueError as e: - pass - try: - return datetime.datetime.strptime(timestr, '%I:%M:%S %p').strftime(self.APP_TIME_FORMAT_STR) - except ValueError as e: - pass - try: - return datetime.datetime.strptime(timestr, '%H:%M').strftime(self.APP_TIME_FORMAT_STR) - except ValueError as e: - pass - return timestr def time_diff(self, time1,time2): @@ -476,12 +333,9 @@ class PseudoChannel(): ''' timeA = datetime.datetime.strptime(time1, '%I:%M:%S %p') timeB = datetime.datetime.strptime(time2, '%I:%M:%S %p') - timeAEpoch = calendar.timegm(timeA.timetuple()) timeBEpoch = calendar.timegm(timeB.timetuple()) - tdelta = abs(timeAEpoch) - abs(timeBEpoch) - return int(tdelta/60) @@ -495,26 +349,16 @@ class PseudoChannel(): def calculate_start_time(self, prevEndTime, intendedStartTime, timeGap, overlapMax): self.TIME_GAP = timeGap - self.OVERLAP_GAP = timeGap - self.OVERLAP_MAX = overlapMax - time1 = prevEndTime.strftime('%I:%M:%S %p') - timeB = datetime.datetime.strptime(intendedStartTime, '%I:%M:%S %p').strftime(self.APP_TIME_FORMAT_STR) - print "++++ Previous End Time: ", time1, "Intended start time: ", timeB - timeDiff = self.time_diff(time1, timeB) - """print("timeDiff "+ str(timeDiff)) print("startTimeUNIX: "+ str(intendedStartTime))""" - newTimeObj = timeB - newStartTime = timeB - ''' * * If time difference is negative, then we know there is overlap @@ -527,32 +371,14 @@ class PseudoChannel(): * ''' timeset=[datetime.time(h,m).strftime("%H:%M") for h,m in itertools.product(xrange(0,24),xrange(0,60,int(self.OVERLAP_GAP)))] - - #print(timeset) - timeSetToUse = None - for time in timeset: - - #print(time) theTimeSetInterval = datetime.datetime.strptime(time, '%H:%M') - - # print(theTimeSetInterval) - - # print(prevEndTime) - if theTimeSetInterval >= prevEndTime: - print "++++ There is overlap. Setting new time-interval:", theTimeSetInterval - newStartTime = theTimeSetInterval - break - - #newStartTime = newTimeObj + datetime.timedelta(minutes=abs(timeDiff + overlapGap)) - elif (timeDiff >= 0) and (self.TIME_GAP != -1): - ''' * * If there this value is configured, then the timeGap var in config will determine the next increment. @@ -560,65 +386,39 @@ class PseudoChannel(): * ''' timeset=[datetime.time(h,m).strftime("%H:%M") for h,m in itertools.product(xrange(0,24),xrange(0,60,int(self.TIME_GAP)))] - - # print(timeset) - for time in timeset: - theTimeSetInterval = datetime.datetime.strptime(time, '%H:%M') - tempTimeTwoStr = datetime.datetime.strptime(time1, self.APP_TIME_FORMAT_STR).strftime('%H:%M') - formatted_time_two = datetime.datetime.strptime(tempTimeTwoStr, '%H:%M') - if theTimeSetInterval >= formatted_time_two: - print "++++ Setting new time-interval:", theTimeSetInterval - newStartTime = theTimeSetInterval - break - else: - print("Not sure what to do here") - return newStartTime.strftime('%I:%M:%S %p') def get_end_time_from_duration(self, startTime, duration): time = datetime.datetime.strptime(startTime, '%I:%M:%S %p') - show_time_plus_duration = time + datetime.timedelta(milliseconds=duration) - - #print(show_time_plus_duration.minute) - return show_time_plus_duration def generate_daily_schedule(self): print("#### Generating Daily Schedule") - logging.info("##### Dropping previous daily_schedule database") - - """A fix for the duplicate entries problem that comes up occasionally.""" self.db.drop_daily_schedule_table() - sleep(1) - self.db.create_daily_schedule_table() - sleep(1) - if self.USING_COMMERCIAL_INJECTION: self.commercials = PseudoChannelCommercial( self.db.get_commercials(), self.COMMERCIAL_PADDING_IN_SECONDS ) - schedule = self.db.get_schedule() - weekday_dict = { "0" : ["mondays", "weekdays", "everyday"], "1" : ["tuesdays", "weekdays", "everyday"], @@ -628,33 +428,19 @@ class PseudoChannel(): "5" : ["saturdays", "weekends", "everyday"], "6" : ["sundays", "weekends", "everyday"], } - weekno = datetime.datetime.today().weekday() - schedule_advance_watcher = 0 - for entry in schedule: - schedule_advance_watcher += 1 - section = entry[9] - for key, val in weekday_dict.iteritems(): - if str(entry[7]) in str(val) and int(weekno) == int(key): - if section == "TV Shows": - if str(entry[3]).lower() == "random": - next_episode = self.db.get_random_episode() - else: - next_episode = self.db.get_next_episode(entry[3]) - if next_episode != None: - episode = Episode( section, # section_type next_episode[3], # title @@ -670,27 +456,15 @@ class PseudoChannel(): next_episode[5], # episode_number next_episode[6] # season_number ) - self.MEDIA.append(episode) - else: - print("Cannot find TV Show Episode, {} in the local db".format(entry[3])) - - #print(episode) - elif section == "Movies": - if str(entry[3]).lower() == "random": - if(entry[13] != ''): - movies = self.PLEX.library.section('Movies') - movies_list = [] - try: - thestr = entry[13] regex = re.compile(r"\b(\w+)\s*:\s*([^:]*)(?=\s+\w+\s*:|$)") d = dict(regex.findall(thestr)) @@ -699,25 +473,15 @@ class PseudoChannel(): d[key] = val.split(',') for movie in movies.search(None, **d): movies_list.append(movie) - the_movie = self.db.get_movie(random.choice(movies_list).title) - except: - print("For some reason, I've failed getting movie with xtra args.") - the_movie = self.db.get_random_movie() - else: - the_movie = self.db.get_random_movie() - else: - the_movie = self.db.get_movie(entry[3]) - if the_movie != None: - movie = Movie( section, # section_type the_movie[3], # title @@ -730,21 +494,12 @@ class PseudoChannel(): entry[12], # overlap_max the_movie[6] # plex id ) - - #print(movie.natural_end_time) - self.MEDIA.append(movie) - else: - print str("Cannot find Movie, {} in the local db".format(entry[3])).encode('UTF-8') - elif section == "Music": - the_music = self.db.get_music(entry[3]) - if the_music != None: - music = Music( section, # section_type the_music[3], # title @@ -757,21 +512,12 @@ class PseudoChannel(): entry[12], # overlap_max the_music[6], # plex id ) - - #print(music.natural_end_time) - self.MEDIA.append(music) - else: - print str("Cannot find Music, {} in the local db".format(entry[3])).encode('UTF-8') - elif section == "Video": - the_video = self.db.get_video(entry[3]) - if the_music != None: - video = Video( section, # section_type the_video[3], # title @@ -784,270 +530,145 @@ class PseudoChannel(): entry[12], # overlap_max the_video[6] # plex id ) - - #print(music.natural_end_time) - self.MEDIA.append(video) - else: - print str("Cannot find Video, {} in the local db".format(entry[3])).encode('UTF-8') - else: - pass - """If we reached the end of the scheduled items for today, add them to the daily schedule """ if schedule_advance_watcher >= len(schedule): - print "+++++ Finished processing time entries, recreating daily_schedule" - previous_episode = None - for entry in self.MEDIA: - - #print entry.natural_end_time - if previous_episode != None: - natural_start_time = datetime.datetime.strptime(entry.natural_start_time, self.APP_TIME_FORMAT_STR) - natural_end_time = entry.natural_end_time - if entry.is_strict_time.lower() == "true": - print "++++ Strict-time: {}".format(str(entry.title)) - entry.end_time = self.get_end_time_from_duration( self.translate_time(entry.start_time), entry.duration ) - """Get List of Commercials to inject""" - if self.USING_COMMERCIAL_INJECTION: - list_of_commercials = self.commercials.get_commercials_to_place_between_media( previous_episode, entry ) - for commercial in list_of_commercials: - self.db.add_media_to_daily_schedule(commercial) - self.db.add_media_to_daily_schedule(entry) - previous_episode = entry - else: - try: print "++++ NOT strict-time: {}".format(str(entry.title).encode(sys.stdout.encoding, errors='replace')) - except: - pass - new_starttime = self.calculate_start_time( previous_episode.end_time, entry.natural_start_time, previous_episode.time_shift, previous_episode.overlap_max ) - print "++++ New start time:", new_starttime - entry.start_time = datetime.datetime.strptime(new_starttime, self.APP_TIME_FORMAT_STR).strftime('%I:%M:%S %p') - entry.end_time = self.get_end_time_from_duration(entry.start_time, entry.duration) - """Get List of Commercials to inject""" if self.USING_COMMERCIAL_INJECTION: list_of_commercials = self.commercials.get_commercials_to_place_between_media( previous_episode, entry ) - for commercial in list_of_commercials: - self.db.add_media_to_daily_schedule(commercial) - self.db.add_media_to_daily_schedule(entry) - previous_episode = entry - else: - self.db.add_media_to_daily_schedule(entry) - previous_episode = entry - self.make_xml_schedule() def run_commercial_injection(self): - """print "#### Running commercial injection." - - self.commercials = PseudoChannelCommercial( - self.db.get_commercials(), - self.db.get_daily_schedule() - ) - - commercials_to_inject = self.commercials.get_commercials_to_inject() - - print commercials_to_inject""" - - pass - - def run(self): - - """print datetime.datetime.now() - threading.Timer(1, self.run()).start()""" pass def make_xml_schedule(self): self.controller.make_xml_schedule(self.db.get_daily_schedule()) - def get_daily_schedule_as_media_object_list(self): - - for i, item in enumerate(self.db.get_daily_schedule(), start=0): - - if item[11] == "TV Shows": - - """episode = Episode( - - )""" - pass - - elif item[11] == "Movies": - - pass - - elif item[11] == "Music": - - pass - - elif item[11] == "Commercials": - - pass - - elif item[11] == "Videos": - - pass - - else: - - pass - def show_clients(self): print "##### Connected Clients:" - for i, client in enumerate(self.PLEX.clients()): - print "+++++", str(i + 1)+".", "Client:", client.title def show_schedule(self): print "##### Daily Pseudo Schedule:" - daily_schedule = self.db.get_daily_schedule() - for i , entry in enumerate(daily_schedule): - print str("+++++ {} {} {} {} {} {}".format(str(i + 1)+".", entry[8], entry[11], entry[6], " - ", entry[3])).encode(sys.stdout.encoding, errors='replace') def write_json_to_file(self, data): - fileName = "pseudo-schedule.json" - + fileName = "pseudo-queue.json" 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) def export_queue(self): shows_table = self.db.get_shows_table() - json_string = json.dumps(shows_table) - - print "+++++ Exporting queue ", json_string - + print "+++++ Exporting queue " self.write_json_to_file(json_string) + print "+++++ Done." def import_queue(self): """Dropping previous shows table before adding the imported data""" - self.db.clear_shows_table() - - with open('pseudo-schedule.json') as data_file: + with open('pseudo-queue.json') as data_file: data = json.load(data_file) - - pprint(data) - + #pprint(data) for row in data: - print row - self.db.import_shows_table_by_row(row[2], row[3], row[4], row[5], row[6], row[7]) + print "+++++ Done. Imported queue." def get_daily_schedule_cache_as_json(self): data = [] - try: with open('../.pseudo-cache/daily-schedule.json') as data_file: data = json.load(data_file) - #pprint(data) - except IOError: - print ("----- Having issues opening the pseudo-cache file.") - return data def save_daily_schedule_as_json(self): daily_schedule_table = self.db.get_daily_schedule() - json_string = json.dumps(daily_schedule_table) - print "+++++ Saving Daily Schedule Cache " - self.save_file(json_string, 'daily-schedule.json', '../.pseudo-cache/') def save_file(self, data, filename, path="./"): fileName = filename - writepath = path - 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) def rotate_log(self): @@ -1056,7 +677,6 @@ class PseudoChannel(): os.remove('../pseudo-channel.log') except OSError: pass - try: os.remove('./pseudo-channel.log') except OSError: @@ -1065,31 +685,16 @@ class PseudoChannel(): def exit_app(self): print " - Exiting Pseudo TV & cleaning up." - for i in self.MEDIA: - del i - self.MEDIA = None - self.controller = None - self.db = None - sleep(1) if __name__ == '__main__': pseudo_channel = PseudoChannel() - - #pseudo_channel.db.create_tables() - - #pseudo_channel.update_db() - - #pseudo_channel.update_schedule() - - #pseudo_channel.generate_daily_schedule() - banner = textwrap.dedent('''\ # __ __ # |__)_ _ _| _ / |_ _ _ _ _| _ @@ -1098,17 +703,14 @@ if __name__ == '__main__': A Custom TV Channel for Plex ''') - parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description = banner) - ''' * * Primary arguments: "python PseudoChannel.py -u -xml -g -r" * ''' - parser.add_argument('-u', '--update', action='store_true', help='Update the local database with Plex libraries.') @@ -1123,14 +725,12 @@ if __name__ == '__main__': parser.add_argument('-gc', '--google_calendar', action='store_true', help='Update the local database with entries in the google calendar.') - parser.add_argument('-g', '--generate_schedule', action='store_true', help='Generate the daily schedule.') parser.add_argument('-r', '--run', action='store_true', help='Run this program.') - ''' * * Show connected clients: "python PseudoChannel.py -c" @@ -1139,7 +739,6 @@ if __name__ == '__main__': parser.add_argument('-c', '--show_clients', action='store_true', help='Show Plex clients.') - ''' * * Show schedule (daily): "python PseudoChannel.py -s" @@ -1148,7 +747,6 @@ if __name__ == '__main__': parser.add_argument('-s', '--show_schedule', action='store_true', help='Show scheduled media for today.') - ''' * * Make XML / HTML Schedule: "python PseudoChannel.py -m" @@ -1157,7 +755,6 @@ if __name__ == '__main__': parser.add_argument('-m', '--make_html', action='store_true', help='Makes the XML / HTML schedule based on the daily_schedule table.') - ''' * * Export queue: "python PseudoChannel.py -e" @@ -1166,7 +763,6 @@ if __name__ == '__main__': parser.add_argument('-e', '--export_queue', action='store_true', help='Exports the current queue for episodes.') - ''' * * Import queue: "python PseudoChannel.py -i" @@ -1175,55 +771,30 @@ if __name__ == '__main__': parser.add_argument('-i', '--import_queue', action='store_true', help='Imports the current queue for episodes.') - globals().update(vars(parser.parse_args())) - args = parser.parse_args() - - #print(args) - if args.update: - pseudo_channel.update_db() - if args.xml: - pseudo_channel.update_schedule() - if args.google_calendar: - pseudo_channel.update_schedule_from_google_calendar() - if args.generate_schedule: - pseudo_channel.generate_daily_schedule() - if args.show_clients: - pseudo_channel.show_clients() - if args.show_schedule: - pseudo_channel.show_schedule() - if args.make_html: - pseudo_channel.make_xml_schedule() - if args.export_queue: - pseudo_channel.export_queue() - if args.import_queue: - pseudo_channel.import_queue() - if args.run: - print banner print "+++++ To run this in the background:" print "+++++", "screen -d -m bash -c 'python PseudoChannel.py -r; exec sh'" - """Every minute on the minute check the DB startTimes of all media to determine whether or not to play. Also, check the now_time to see if it's midnight (or 23.59), if so then generate a new daily_schedule @@ -1232,215 +803,124 @@ if __name__ == '__main__': """Every rotate log""" dayToRotateLog = pseudo_channel.ROTATE_LOG.lower() schedule.every().friday.at("00:00").do(pseudo_channel.rotate_log) - logging.info("+++++ Running PseudoChannel.py -r") - def trigger_what_should_be_playing_now(): def nearest(items, pivot): return min(items, key=lambda x: abs(x - pivot)) daily_schedule = pseudo_channel.db.get_daily_schedule() - dates_list = [datetime.datetime.strptime(''.join(str(date[8])), "%I:%M:%S %p") for date in daily_schedule] - now = datetime.datetime.now() - now = now.replace(year=1900, month=1, day=1) - closest_media = nearest(dates_list, now) - print closest_media - prevItem = None for item in daily_schedule: - item_time = datetime.datetime.strptime(''.join(str(item[8])), "%I:%M:%S %p") if item_time == closest_media: - #print "Line 1088, Here", item - elapsed_time = closest_media - now - print elapsed_time.total_seconds() - try: - endTime = datetime.datetime.strptime(item[9], '%Y-%m-%d %H:%M:%S.%f') - except ValueError: - endTime = datetime.datetime.strptime(item[9], '%Y-%m-%d %H:%M:%S') - # we need to play the content and add an offest if elapsed_time.total_seconds() < 0 and \ endTime > now: - print str("+++++ Queueing up {} to play right away.".format(item[3])).encode('UTF-8') - offset = int(abs(elapsed_time.total_seconds() * 1000)) - pseudo_channel.controller.play(item, daily_schedule, offset) - break - elif elapsed_time.total_seconds() >= 0: - for itemTwo in daily_schedule: - item_timeTwo = datetime.datetime.strptime(''.join(str(itemTwo[8])), "%I:%M:%S %p") - try: - endTime = datetime.datetime.strptime(itemTwo[9], '%Y-%m-%d %H:%M:%S.%f') - except ValueError: - endTime = datetime.datetime.strptime(itemTwo[9], '%Y-%m-%d %H:%M:%S') - if item_timeTwo == closest_media and prevItem != None and \ endTime > now: - prevItem_time = datetime.datetime.strptime(''.join(str(prevItem[8])), "%I:%M:%S %p") - elapsed_timeTwo = prevItem_time - now - offsetTwo = int(abs(elapsed_timeTwo.total_seconds() * 1000)) - if pseudo_channel.DEBUG: print "+++++ Closest media was the next media " \ "but we were in the middle of something so triggering that instead." - print str("+++++ Queueing up '{}' to play right away.".format(prevItem[3])).encode('UTF-8') - pseudo_channel.controller.play(prevItem, daily_schedule, offsetTwo) - break - prevItem = itemTwo - - def job_that_executes_once(item, schedulelist): print str("##### Readying media: '{}'".format(item[3])).encode('UTF-8') - next_start_time = datetime.datetime.strptime(item[8], "%I:%M:%S %p") - now = datetime.datetime.now() - now = now.replace(year=1900, month=1, day=1) - time_diff = next_start_time - now if time_diff.total_seconds() > 0: - - print "+++++ Sleeping for {} seconds before playing: '{}'".format(time_diff.total_seconds(), item[3]) - sleep(int(time_diff.total_seconds())) - if pseudo_channel.DEBUG: print "+++++ Woke up!" - pseudo_channel.controller.play(item, schedulelist) - else: - pseudo_channel.controller.play(item, schedulelist) - return schedule.CancelJob - def generate_memory_schedule(schedulelist, isforupdate=False): print "##### Generating Memory Schedule." - now = datetime.datetime.now() - now = now.replace(year=1900, month=1, day=1) - pseudo_cache = pseudo_channel.get_daily_schedule_cache_as_json() - prev_end_time_to_watch_for = None - if pseudo_channel.USE_OVERRIDE_CACHE and isforupdate: - for cached_item in pseudo_cache: - prev_start_time = datetime.datetime.strptime(cached_item[8], "%I:%M:%S %p") - try: - prev_end_time = datetime.datetime.strptime(cached_item[9], '%Y-%m-%d %H:%M:%S.%f') - except ValueError: - prev_end_time = datetime.datetime.strptime(cached_item[9], '%Y-%m-%d %H:%M:%S') - """If update time is in between the prev media start / stop then there is overlap""" if prev_start_time < now and prev_end_time > now: - try: - print "+++++ It looks like there is update schedule overlap", cached_item[3] - except: - pass - prev_end_time_to_watch_for = prev_end_time - for item in schedulelist: - trans_time = datetime.datetime.strptime(item[8], "%I:%M:%S %p").strftime("%H:%M") - new_start_time = datetime.datetime.strptime(item[8], "%I:%M:%S %p") - if prev_end_time_to_watch_for == None: - schedule.every().day.at(trans_time).do(job_that_executes_once, item, schedulelist).tag('daily-tasks') - else: - """If prev end time is more then the start time of this media, skip it""" if prev_end_time_to_watch_for > new_start_time: - try: - print "Skipping scheduling item do to cached overlap.", item[3] - except: - pass - continue - else: - schedule.every().day.at(trans_time).do(job_that_executes_once, item, schedulelist).tag('daily-tasks') - - print "+++++ Done." - generate_memory_schedule(pseudo_channel.db.get_daily_schedule()) - daily_update_time = datetime.datetime.strptime( pseudo_channel.translate_time( pseudo_channel.DAILY_UPDATE_TIME ), pseudo_channel.APP_TIME_FORMAT_STR ).strftime('%H:%M') - if pseudo_channel.USING_GOOGLE_CALENDAR: - schedule.every().day.at(daily_update_time).do( pseudo_channel.update_schedule_from_google_calendar ).tag('daily-update-gc') - else: - pass def go_generate_daily_sched(): @@ -1455,26 +935,15 @@ if __name__ == '__main__': schedule.every().day.at(daily_update_time).do( go_generate_daily_sched ).tag('daily-update') - sleep_before_triggering_play_now = 1 try: - while True: - schedule.run_pending() - sleep(1) - if sleep_before_triggering_play_now: - logging.info("+++++ Successfully started PseudoChannel.py") - trigger_what_should_be_playing_now() - sleep_before_triggering_play_now = 0 - except KeyboardInterrupt: - - print(' Manual break by user') - \ No newline at end of file + print(' Manual break by user') \ No newline at end of file diff --git a/pseudo_config.py b/pseudo_config.py index 797d8ce..db743c1 100644 --- a/pseudo_config.py +++ b/pseudo_config.py @@ -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. diff --git a/pseudo_schedule.xml b/pseudo_schedule.xml index bac2e98..3090b8c 100644 --- a/pseudo_schedule.xml +++ b/pseudo_schedule.xml @@ -24,7 +24,7 @@ by adding a '' 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 & Friends" playing only on "weekday" mornings scheduled for after Looney Tunes starting at "8:00 AM". Also notice that "Garfield & Friends" below is actually written as, "Garfield & Friends". This is especially important -to those new to editing XML. In XML, "UTF-8", you are forbidden from using certain characters like the "&" +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 "