348 lines
11 KiB
Python
348 lines
11 KiB
Python
import mc
|
|
import re
|
|
import mythtv
|
|
from mythtv import MythError
|
|
from operator import itemgetter, attrgetter
|
|
|
|
|
|
class MythBoxee:
|
|
logLevel = 1
|
|
version = "4.0.beta"
|
|
|
|
userAgent = "MythBoxee v4.0.beta"
|
|
tvdb_apikey = "6BEAB4CB5157AAE0"
|
|
|
|
be = None
|
|
db = None
|
|
|
|
recs = None
|
|
titles = []
|
|
recordings = []
|
|
banners = {}
|
|
shows = {}
|
|
series = {}
|
|
|
|
|
|
"""
|
|
DiscoverBackend - just as it sounds
|
|
|
|
Attempt to discover the MythTV Backend using UPNP protocol, once found
|
|
try and gather MySQL database connection information using default PIN
|
|
via the XML interface. If that fails then prompt user to enter their
|
|
custom SecurityPin, if we fail to gather database information that way
|
|
finally prompt user to enter their credentials manually.
|
|
"""
|
|
def DiscoverBackend():
|
|
self.log("def(DiscoverBackend)")
|
|
|
|
pin = self.config.GetValue("pin")
|
|
dbconn = self.config.GetValue("dbconn")
|
|
|
|
if not pin:
|
|
pin = 0000
|
|
|
|
try:
|
|
self.db = mythtv.MythDB(SecurityPin=pin)
|
|
except Exception, e:
|
|
if e.ename == 'DB_CREDENTIALS' and count < 2:
|
|
mc.ActivateWindow(14002)
|
|
mc.GetWindow(14002).GetControl(6020).SetVisible(False)
|
|
mc.GetWindow(14002).GetControl(6010).SetVisible(True)
|
|
mc.GetWindow(14002).GetControl(6011).SetFocus()
|
|
elif e.ename == 'DB_CONNECTION' or e.ename == 'DB_CREDENTIALS' and count > 3:
|
|
mc.ActivateWindow(14002)
|
|
mc.GetWindow(14002).GetControl(6010).SetVisible(False)
|
|
mc.GetWindow(14002).GetControl(6020).SetVisible(True)
|
|
mc.GetWindow(14002).GetControl(6021).SetFocus()
|
|
return False
|
|
else:
|
|
self.config.SetValue("dbconn", str(self.db.dbconn))
|
|
return True
|
|
|
|
|
|
"""
|
|
Lets make a connection to the backend!
|
|
"""
|
|
def __init__(self):
|
|
self.config = mc.GetApp().GetLocalConfig()
|
|
|
|
self.log("def(__init__)")
|
|
|
|
# If this is the first time the app is being run, lets set some default options.
|
|
if not self.config.GetValue("firstrun"):
|
|
self.config.SetValue("SortBy", "Original Air Date")
|
|
self.config.SetValue("SortDir", "Descending")
|
|
self.config.SetValue("firstrun", "1")
|
|
|
|
# If dbconn isn't set, we'll assume we haven't found the backend.
|
|
if not self.config.GetValue("dbconn"):
|
|
discoverBackend = False
|
|
while discoverBackend is False:
|
|
print "discover"
|
|
discoverBackend = self.DiscoverBackend()
|
|
|
|
# Parse our DB info
|
|
dbconn = self.config.GetValue("dbconn")
|
|
dbconf = eval(dbconn)
|
|
|
|
# Now that the backend has been discovered, lets connect.
|
|
try:
|
|
self.db = mythtv.MythDB(**dbconf)
|
|
except MythError, e:
|
|
print e.message
|
|
mc.ShowDialogNotification("Failed to connect to the MythTV Backend")
|
|
else:
|
|
self.be = mythtv.MythBE(db=self.db)
|
|
|
|
"""
|
|
GetRecordings - Pulls all of the recordings out of the backend.
|
|
|
|
This function also creates some dictionarys and lists of information
|
|
that is used throughout the app for different functions.
|
|
"""
|
|
def GetRecordings(self):
|
|
self.titles = []
|
|
self.banners = {}
|
|
self.series = {}
|
|
self.shows = {}
|
|
|
|
self.log("def(GetRecordings)")
|
|
|
|
self.recs = self.be.getRecordings()
|
|
|
|
x=0
|
|
for recording in self.recs:
|
|
if recording.title not in self.titles:
|
|
self.titles.append(str(recording.title))
|
|
self.banners[str(recording.title)] = self.GetRecordingArtwork(str(recording.title))
|
|
self.series[str(recording.title)] = self.GetRecordingSeriesID(str(recording.title))
|
|
self.shows[str(recording.title)] = []
|
|
|
|
single = [str(recording.title), str(recording.subtitle), str(recording.description), str(recording.chanid), str(recording.airdate), str(recording.starttime), str(recording.endtime), x]
|
|
self.shows[str(recording.title)].append(single)
|
|
x = x + 1
|
|
|
|
self.titles.sort()
|
|
|
|
items = mc.ListItems()
|
|
for title in self.titles:
|
|
item = mc.ListItem( mc.ListItem.MEDIA_UNKNOWN )
|
|
item.SetLabel(str(title))
|
|
item.SetThumbnail(self.banners[title])
|
|
item.SetProperty("videos", str(len(self.shows[title])))
|
|
item.SetProperty("seriesid", str(self.series[title]))
|
|
items.append(item)
|
|
|
|
mc.GetWindow(14001).GetList(1030).SetItems(items)
|
|
|
|
|
|
def GetRecordingArtwork(self, title):
|
|
sg = mc.Http()
|
|
sg.SetUserAgent('MythBoxee v4.0.beta')
|
|
html = sg.Get("http://www.thetvdb.com/api/GetSeries.php?seriesname=" + str(title.replace(" ", "%20")))
|
|
banners = re.compile("<banner>(.*?)</banner>").findall(html)
|
|
|
|
try:
|
|
artwork = "http://www.thetvdb.com/banners/" + banners[0]
|
|
except:
|
|
artwork = "mb_artwork_error.png"
|
|
|
|
self.log("def(GetRecordingArtwork): " + str(artwork))
|
|
|
|
return artwork
|
|
|
|
def GetRecordingSeriesID(self, title):
|
|
sg = mc.Http()
|
|
sg.SetUserAgent(self.userAgent)
|
|
html = sg.Get("http://www.thetvdb.com/api/GetSeries.php?seriesname=" + title.replace(" ", "%20"))
|
|
series = re.compile("<seriesid>(.*?)</seriesid>").findall(html)
|
|
|
|
try:
|
|
seriesid = series[0]
|
|
except:
|
|
seriesid = 00000
|
|
|
|
self.log("def(GetRecordingSeriesID): title[" + title + "] - seriesid[" + str(seriesid) + "]")
|
|
|
|
return seriesid
|
|
|
|
|
|
"""
|
|
DisplayShow
|
|
"""
|
|
def DisplayShow(self):
|
|
recordingList = mc.GetWindow(14001).GetList(1030)
|
|
item = recordingList.GetItem(recordingList.GetFocusedItem())
|
|
title = item.GetLabel()
|
|
|
|
# Save the Latest Show Title to what was clicked
|
|
# this way the show window has a way to load the data.
|
|
self.config.SetValue("LatestShowTitle", title)
|
|
self.config.SetValue("LatestShowID", item.GetProperty("seriesid"))
|
|
|
|
self.log("def(DisplaySingleShow): Title[" + title + "]")
|
|
|
|
# Show the Single Show Window
|
|
mc.ActivateWindow(14002)
|
|
|
|
itemList = mc.ListItems()
|
|
itemList.append(item)
|
|
|
|
mc.GetWindow(14002).GetList(2070).SetItems(itemList)
|
|
|
|
|
|
"""
|
|
LoadShow
|
|
|
|
Launch function to gather and setup the recordings for a single show.
|
|
"""
|
|
def LoadShow(self):
|
|
title = self.config.GetValue("LatestShowTitle")
|
|
seriesid = self.config.GetValue("LatestShowID")
|
|
|
|
self.log("def(LoadSingleShow): Title[" + title + "]")
|
|
|
|
self.SetSortableOptions()
|
|
self.SetSeriesDetails(title, seriesid)
|
|
self.LoadShowRecordings(title)
|
|
|
|
|
|
"""
|
|
LoadShowRecordings
|
|
|
|
Determine which show is being displayed and find all the recordings for it.
|
|
Then populate the recording list for the singular show for viewer to watch.
|
|
"""
|
|
def LoadShowRecordings(self, title):
|
|
sortBy = self.config.GetValue("SortBy")
|
|
sortDir = self.config.GetValue("SortDir")
|
|
|
|
episodes = None
|
|
|
|
if sortBy == "Original Air Date" and sortDir == "Ascending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(4))
|
|
elif sortBy == "Original Air Date" and sortDir == "Descending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(4), reverse=True)
|
|
elif sortBy == "Recorded Date" and sortDir == "Ascending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(5))
|
|
elif sortBy == "Recorded Date" and sortDir == "Descending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(5), reverse=True)
|
|
elif sortBy == "Title" and sortDir == "Ascending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(1))
|
|
elif sortBy == "Title" and sortDir == "Descending":
|
|
episodes = sorted(self.shows[title], key=itemgetter(1), reverse=True)
|
|
else:
|
|
episodes = self.shows[title]
|
|
|
|
showitems = mc.ListItems()
|
|
for title,subtitle,desc,chanid,airdate,starttime,endtime,ref in episodes:
|
|
print title
|
|
recording = self.recs[ref]
|
|
#showitem = mc.ListItem( mc.ListItem.MEDIA_VIDEO_EPISODE )
|
|
#showitem = mc.ListItem( mc.ListItem.MEDIA_UNKNOWN )
|
|
showitem = mc.ListItem()
|
|
showitem.SetLabel(str(recording.subtitle))
|
|
showitem.SetTitle(str(recording.subtitle))
|
|
showitem.SetTVShowTitle(str(recording.title))
|
|
showitem.SetDescription(str(desc))
|
|
showitem.SetProperty("starttime", str(starttime))
|
|
showitem.SetProperty("ref", str(ref))
|
|
|
|
try:
|
|
date = str(airdate).split("-")
|
|
showitem.SetDate(int(date[0]), int(date[1]), int(date[2]))
|
|
except:
|
|
showitem.SetDate(2010, 01, 01)
|
|
|
|
dbconf = eval(self.config.GetValue("dbconn"))
|
|
|
|
#showitem.SetThumbnail("http://192.168.1.210:6544/Myth/GetPreviewImage?ChanId=1050&StartTime=2010-08-05%2021:00:00")
|
|
#showitem.SetThumbnail("http://192.168.1.210:6544/Myth/GetPreviewImage?ChanId=" + chanid + "&StartTime=" + starttime.replace("T", "%20"))
|
|
showitem.SetThumbnail("http://" + dbconf['DBHostName'] + ":6544/Myth/GetPreviewImage?ChanId=" + chanid + "&StartTime=" + starttime.replace(" ", "%20"))
|
|
|
|
#showitem.SetPath("http://" + dbconf['DBHostName'] + ":6544/Myth/GetRecording?ChanId=" + chanid + "&StartTime=" + starttime.replace("T", "%20"))
|
|
showitem.SetPath("smb://guest:guest@192.168.1.210/recordings/1050_20100709010000.mpg")
|
|
|
|
showitems.append(showitem)
|
|
|
|
mc.GetWindow(14002).GetList(2040).SetItems(mc.ListItems())
|
|
mc.GetWindow(14002).GetList(2040).SetItems(showitems)
|
|
|
|
|
|
"""
|
|
SetShowOptions
|
|
|
|
Setup the show options; sort by, sort direction, watched vs unwatched
|
|
"""
|
|
def SetSortableOptions(self):
|
|
sortable = ['Original Air Date', 'Recorded Date', 'Title']
|
|
items = mc.ListItems()
|
|
for sorttype in sortable:
|
|
item = mc.ListItem( mc.ListItem.MEDIA_UNKNOWN )
|
|
item.SetLabel(sorttype)
|
|
items.append(item)
|
|
|
|
mc.GetWindow(14002).GetList(2051).SetItems(items)
|
|
mc.GetWindow(14002).GetList(2051).SetSelected(1, True)
|
|
|
|
sortableby = ['Ascending', 'Descending']
|
|
items = mc.ListItems()
|
|
for sorttype in sortableby:
|
|
item = mc.ListItem( mc.ListItem.MEDIA_UNKNOWN )
|
|
item.SetLabel(sorttype)
|
|
items.append(item)
|
|
|
|
mc.GetWindow(14002).GetList(2061).SetItems(items)
|
|
mc.GetWindow(14002).GetList(2061).SetSelected(1, True)
|
|
|
|
|
|
def SetSeriesDetails(self, title, seriesid):
|
|
sg = mc.Http()
|
|
sg.SetUserAgent(self.userAgent)
|
|
html = sg.Get("http://thetvdb.com/api/" + self.tvdb_apikey + "/series/" + seriesid + "/")
|
|
overview = re.compile("<Overview>(.*?)</Overview>").findall(html)
|
|
poster = re.compile("<poster>(.*?)</poster>").findall(html)
|
|
items = mc.ListItems()
|
|
item = mc.ListItem( mc.ListItem.MEDIA_UNKNOWN )
|
|
item.SetLabel(title)
|
|
item.SetTitle(title)
|
|
try:
|
|
item.SetDescription(overview[0])
|
|
item.SetProperty("description", overview[0])
|
|
except:
|
|
item.SetDescription("No Description")
|
|
item.SetProperty("description", "No Description")
|
|
|
|
try:
|
|
item.SetThumbnail("http://www.thetvdb.com/banners/" + poster[0])
|
|
except:
|
|
item.SetThumbnail("mb_poster_error.png")
|
|
|
|
items.append(item)
|
|
|
|
mc.GetWindow(14002).GetList(2070).SetItems(items)
|
|
|
|
|
|
def PlayRecording(self):
|
|
self.log("def(PlayRecording): ")
|
|
|
|
sl = mc.GetWindow(14002).GetList(2040)
|
|
item = sl.GetItem(sl.GetFocusedItem())
|
|
|
|
ref = item.GetProperty("ref")
|
|
|
|
file = self.recs[int(ref)].open('r', self.db)
|
|
|
|
mc.ShowDialogNotification(item.GetProperty("ref"))
|
|
mc.ShowDialogNotification("Playing: " + item.GetLabel())
|
|
|
|
|
|
def log(self, message):
|
|
if self.logLevel >= 2:
|
|
mc.ShowDialogNotification(message)
|
|
|
|
if self.logLevel >= 1:
|
|
mc.LogInfo(">>> MythBoxee (" + self.version + ")\: " + message)
|
|
|
|
print ">>> MythBoxee (" + self.version + ")\: " + message
|