Added commercial support. Currently seems to be working ok, but needs adjusting / testing. Currently am using it with a time-shift of '5'.

This commit is contained in:
Justin Emter
2017-07-25 18:32:22 -07:00
parent ab9f69de5f
commit 8b2e69fc3e
6 changed files with 268 additions and 50 deletions

View File

@@ -9,6 +9,7 @@ from src import Music
from src import Video from src import Video
from src import PseudoDailyScheduleController from src import PseudoDailyScheduleController
from src import GoogleCalendar from src import GoogleCalendar
from src import PseudoChannelCommercial
from plexapi.server import PlexServer from plexapi.server import PlexServer
@@ -36,6 +37,8 @@ class PseudoChannel():
GKEY = config.gkey GKEY = config.gkey
USING_GOOGLE_CALENDAR = config.useGoogleCalendar USING_GOOGLE_CALENDAR = config.useGoogleCalendar
USING_COMMERCIAL_INJECTION = config.useCommercialInjection
def __init__(self): def __init__(self):
self.db = PseudoChannelDatabase("pseudo-channel.db") self.db = PseudoChannelDatabase("pseudo-channel.db")
@@ -243,7 +246,7 @@ class PseudoChannel():
title = titlelist[1] title = titlelist[1]
# s.strftime('%I:%M'), event["summary"] # s.strftime('%I:%M'), event["summary"]
natural_start_time = self.translate_time(s.strftime('%I:%M %p')) natural_start_time = self.translate_time(s.strftime('%I:%M:%S %p'))
natural_end_time = 0 natural_end_time = 0
@@ -259,6 +262,8 @@ class PseudoChannel():
strict_time = titlelist[2] if len(titlelist) > 2 else "true" strict_time = titlelist[2] if len(titlelist) > 2 else "true"
#strict_time = "true"
time_shift = "5" time_shift = "5"
overlap_max = "" overlap_max = ""
@@ -267,7 +272,7 @@ class PseudoChannel():
start_time_unix = datetime.datetime.strptime( start_time_unix = datetime.datetime.strptime(
self.translate_time(natural_start_time), self.translate_time(natural_start_time),
'%I:%M %p').strftime('%Y-%m-%d %H:%M:%S') '%I:%M:%S %p').strftime('%Y-%m-%d %H:%M:%S')
#print "Adding: ", time.tag, section, time.text, time.attrib['title'] #print "Adding: ", time.tag, section, time.text, time.attrib['title']
@@ -343,7 +348,7 @@ class PseudoChannel():
start_time_unix = datetime.datetime.strptime( start_time_unix = datetime.datetime.strptime(
self.translate_time(time.text), self.translate_time(time.text),
'%I:%M %p').strftime('%Y-%m-%d %H:%M:%S') '%I:%M:%S %p').strftime('%Y-%m-%d %H:%M:%S')
print "Adding: ", time.tag, section, time.text, time.attrib['title'] print "Adding: ", time.tag, section, time.text, time.attrib['title']
@@ -398,7 +403,7 @@ class PseudoChannel():
try: try:
return datetime.datetime.strptime(timestr, "%I:%M %p").strftime("%-I:%M %p") return datetime.datetime.strptime(timestr, '%I:%M:%S %p').strftime('%I:%M:%S %p')
except ValueError as e: except ValueError as e:
@@ -406,7 +411,7 @@ class PseudoChannel():
try: try:
return datetime.datetime.strptime(timestr, "%H:%M").strftime("%-I:%M %p") return datetime.datetime.strptime(timestr, '%I:%M:%S %p').strftime('%I:%M:%S %p')
except ValueError as e: except ValueError as e:
@@ -418,8 +423,8 @@ class PseudoChannel():
* Getting the offest by comparing both times from the unix epoch time and getting the difference. * Getting the offest by comparing both times from the unix epoch time and getting the difference.
* *
''' '''
timeA = datetime.datetime.strptime(time1, "%I:%M %p") timeA = datetime.datetime.strptime(time1, '%I:%M:%S %p')
timeB = datetime.datetime.strptime(time2, "%I:%M %p") timeB = datetime.datetime.strptime(time2, '%I:%M:%S %p')
timeAEpoch = calendar.timegm(timeA.timetuple()) timeAEpoch = calendar.timegm(timeA.timetuple())
timeBEpoch = calendar.timegm(timeB.timetuple()) timeBEpoch = calendar.timegm(timeB.timetuple())
@@ -444,9 +449,9 @@ class PseudoChannel():
self.OVERLAP_MAX = overlapMax self.OVERLAP_MAX = overlapMax
time1 = prevEndTime.strftime('%-I:%M %p') time1 = prevEndTime.strftime('%I:%M:%S %p')
timeB = datetime.datetime.strptime(intendedStartTime, '%I:%M %p').strftime('%-I:%M %p') timeB = datetime.datetime.strptime(intendedStartTime, '%I:%M:%S %p').strftime('%I:%M:%S %p')
print "++++ Previous End Time: ", time1, "Intended start time: ", timeB print "++++ Previous End Time: ", time1, "Intended start time: ", timeB
@@ -511,7 +516,7 @@ class PseudoChannel():
theTimeSetInterval = datetime.datetime.strptime(time, '%H:%M') theTimeSetInterval = datetime.datetime.strptime(time, '%H:%M')
tempTimeTwoStr = datetime.datetime.strptime(time1, '%I:%M %p').strftime('%H:%M') tempTimeTwoStr = datetime.datetime.strptime(time1, '%I:%M:%S %p').strftime('%H:%M')
formatted_time_two = datetime.datetime.strptime(tempTimeTwoStr, '%H:%M') formatted_time_two = datetime.datetime.strptime(tempTimeTwoStr, '%H:%M')
@@ -527,11 +532,11 @@ class PseudoChannel():
print("Not sure what to do here") print("Not sure what to do here")
return newStartTime.strftime('%-I:%M %p') return newStartTime.strftime('%I:%M:%S %p')
def get_end_time_from_duration(self, startTime, duration): def get_end_time_from_duration(self, startTime, duration):
time = datetime.datetime.strptime(startTime, '%I:%M %p') time = datetime.datetime.strptime(startTime, '%I:%M:%S %p')
show_time_plus_duration = time + datetime.timedelta(milliseconds=duration) show_time_plus_duration = time + datetime.timedelta(milliseconds=duration)
@@ -543,6 +548,11 @@ class PseudoChannel():
print("#### Generating Daily Schedule") print("#### Generating Daily Schedule")
if self.USING_COMMERCIAL_INJECTION:
self.commercials = PseudoChannelCommercial(
self.db.get_commercials()
)
schedule = self.db.get_schedule() schedule = self.db.get_schedule()
weekday_dict = { weekday_dict = {
@@ -713,7 +723,7 @@ class PseudoChannel():
if previous_episode != None: if previous_episode != None:
natural_start_time = datetime.datetime.strptime(entry.natural_start_time, '%I:%M %p') natural_start_time = datetime.datetime.strptime(entry.natural_start_time, '%I:%M:%S %p')
natural_end_time = entry.natural_end_time natural_end_time = entry.natural_end_time
@@ -726,6 +736,19 @@ class PseudoChannel():
entry.duration 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) self.db.add_media_to_daily_schedule(entry)
previous_episode = entry previous_episode = entry
@@ -743,10 +766,21 @@ class PseudoChannel():
print "++++ New start time:", new_starttime print "++++ New start time:", new_starttime
entry.start_time = datetime.datetime.strptime(new_starttime, '%I:%M %p').strftime('%-I:%M %p') entry.start_time = datetime.datetime.strptime(new_starttime, '%I:%M:%S %p').strftime('%I:%M:%S %p')
entry.end_time = self.get_end_time_from_duration(entry.start_time, entry.duration) 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) self.db.add_media_to_daily_schedule(entry)
previous_episode = entry previous_episode = entry
@@ -757,6 +791,19 @@ class PseudoChannel():
previous_episode = entry previous_episode = entry
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
def make_xml_schedule(self): def make_xml_schedule(self):
self.controller.make_xml_schedule(self.db.get_daily_schedule()) self.controller.make_xml_schedule(self.db.get_daily_schedule())
@@ -906,6 +953,15 @@ if __name__ == '__main__':
action='store_true', action='store_true',
help='Makes the XML / HTML schedule based on the daily_schedule table.') help='Makes the XML / HTML schedule based on the daily_schedule table.')
'''
*
* Make XML / HTML Schedule: "python PseudoChannel.py -i"
*
'''
parser.add_argument('-i', '--inject_commercials',
action='store_true',
help='Squeeze commercials in any media gaps if possible.')
globals().update(vars(parser.parse_args())) globals().update(vars(parser.parse_args()))
args = parser.parse_args() args = parser.parse_args()
@@ -940,6 +996,10 @@ if __name__ == '__main__':
pseudo_channel.make_xml_schedule() pseudo_channel.make_xml_schedule()
if args.inject_commercials:
pseudo_channel.run_commercial_injection()
if args.run: if args.run:
try: try:
@@ -977,9 +1037,9 @@ if __name__ == '__main__':
t = datetime.datetime.utcnow() t = datetime.datetime.utcnow()
sleeptime = 60 - (t.second + t.microsecond/1000000.0) #sleeptime = 60 - (t.second + t.microsecond/1000000.0)
sleep(sleeptime) sleep(.5)
except KeyboardInterrupt, e: except KeyboardInterrupt, e:

View File

@@ -59,3 +59,5 @@ plexLibraries = {
} }
useGoogleCalendar = True useGoogleCalendar = True
useCommercialInjection = True

View File

@@ -0,0 +1,133 @@
"""Commercial Functionality
"""
from random import shuffle
import random
import copy
import datetime
from src import Commercial
class PseudoChannelCommercial():
MIN_DURATION_FOR_COMMERCIAL = 10 #seconds
daily_schedule = []
def __init__(self, commercials):
self.commercials = commercials
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 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.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.datetime.strptime(now_ep.start_time, '%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()
new_commercial_seconds = (int(random_commercial[4])/1000)%60
commercial_dur_sum += new_commercial_seconds
new_commercial_start_time = prev_item_end_time + datetime.timedelta(seconds=commercial_dur_sum)
new_commercial_end_time = new_commercial_start_time + datetime.timedelta(seconds=int(new_commercial_seconds))
formatted_time_for_new_commercial = new_commercial_start_time.strftime('%I:%M:%S %p')
new_commercial = Commercial(
"Commercials",
random_commercial[3],
formatted_time_for_new_commercial, # natural_start_time
new_commercial_end_time,
random_commercial[4],
"everyday", # day_of_week
"true", # is_strict_time
"1", # time_shift
"0", # overlap_max
"", # plex_media_id
)
commercial_list.append(new_commercial)
#print "here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
return commercial_list

View File

@@ -329,6 +329,14 @@ class PseudoChannelDatabase():
return self.get_media(title, media) 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): def update_shows_table_with_last_episode(self, showTitle, lastEpisodeTitle):
sql1 = "UPDATE shows SET lastEpisodeTitle = ? WHERE title LIKE ? COLLATE NOCASE" sql1 = "UPDATE shows SET lastEpisodeTitle = ? WHERE title LIKE ? COLLATE NOCASE"
@@ -461,7 +469,7 @@ class PseudoChannelDatabase():
return first_episode return first_episode
def get_commercials(self, title): def get_commercial(self, title):
media = "commercials" media = "commercials"

View File

@@ -73,7 +73,7 @@ class PseudoDailyScheduleController():
for row in datalist: for row in datalist:
timeB = datetime.strptime(row[8], '%I:%M %p') timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime == None: if currentTime == None:
@@ -188,7 +188,7 @@ class PseudoDailyScheduleController():
with tag('tbody'): with tag('tbody'):
timeB = datetime.strptime(row[8], '%I:%M %p') timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime == None: if currentTime == None:
@@ -333,6 +333,16 @@ class PseudoDailyScheduleController():
clientItem.playMedia(movie) 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: else:
print("Not sure how to play {}".format(mediaType)) print("Not sure how to play {}".format(mediaType))
@@ -367,12 +377,14 @@ class PseudoDailyScheduleController():
if currentTime.minute == endTime.minute: if currentTime.minute == endTime.minute:
print("Ok end time found") if currentTime.second == endTime.second:
self.write_schedule_to_file(self.get_html_from_daily_schedule(None, None, datalist)) print("Ok end time found")
self.write_xml_to_file(self.get_xml_from_daily_schedule(None, None, datalist))
break 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 * Check DB / current time. If that matches a scheduled shows startTime then trigger play via Plex API
@@ -394,44 +406,46 @@ class PseudoDailyScheduleController():
for row in datalist: for row in datalist:
timeB = datetime.strptime(row[8], '%I:%M %p') timeB = datetime.strptime(row[8], '%I:%M:%S %p')
if currentTime.hour == timeB.hour: if currentTime.hour == timeB.hour:
if currentTime.minute == timeB.minute: if currentTime.minute == timeB.minute:
print("Starting Epsisode: " + row[3]) if currentTime.second == timeB.second:
print(row)
self.play_media(row[11], row[6], row[3]) print("Starting Media: " + row[3])
print(row)
self.write_schedule_to_file( self.play_media(row[11], row[6], row[3])
self.get_html_from_daily_schedule(
timeB, self.write_schedule_to_file(
self.get_show_photo( self.get_html_from_daily_schedule(
row[11], timeB,
row[6] if row[11] == "TV Shows" else row[3] self.get_show_photo(
), row[11],
datalist row[6] if row[11] == "TV Shows" else row[3]
),
datalist
)
) )
)
"""Generate / write XML to file """Generate / write XML to file
""" """
self.write_xml_to_file( self.write_xml_to_file(
self.get_xml_from_daily_schedule( self.get_xml_from_daily_schedule(
timeB, timeB,
self.get_show_photo( self.get_show_photo(
row[11], row[11],
row[6] if row[11] == "TV Shows" else row[3] row[6] if row[11] == "TV Shows" else row[3]
), ),
datalist datalist
)
) )
)
self.my_logger.debug('Trying to play: ' + row[3]) self.my_logger.debug('Trying to play: ' + row[3])
break break
datalistLengthMonitor += 1 datalistLengthMonitor += 1

View File

@@ -6,4 +6,5 @@ from Media import Media
from Music import Music from Music import Music
from Video import Video from Video import Video
from PseudoDailyScheduleController import PseudoDailyScheduleController from PseudoDailyScheduleController import PseudoDailyScheduleController
from GoogleCalendar import GoogleCalendar from GoogleCalendar import GoogleCalendar
from PseudoChannelCommercial import PseudoChannelCommercial