123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
-
- Log("\n*** PlayStream started ***\n")
- try:
- import wingdbstub
- except:
- pass
-
- VERSION = "0.1.33"
- CHANNEL_NAME = "PlayStream"
- PREFIX = '/video/playstream'
- DEV = True if Platform.MachineIdentifier == 'Unit testing' else False
- REPO_URL = "http://files.blue.lv/PlayStream.bundle/?sort=time&order=asc"
- DOWNLOAD_URL = "http://files.blue.lv/PlayStream.bundle/"
- ART = "art-default.jpg"
- ICON = "icon-default.png"
- BACK = "back.png"
- FOLDER = "folder.png"
- VIDEO = "video.png"
- SEARCH = "folder_search.png"
- PREFS = "prefs.png"
- UPDATE = "update.png"
-
- import sys, os, re
- import traceback, glob, inspect, urllib, zipfile
- import requests
-
- import content
- from content.ContentSources import ContentSources
- from content import util
-
- import Framework
- #from Framework.api.objectkit import *
- from DumbTools import DumbKeyboard, DumbPrefs
- #C:\Users\user\AppData\Local\Plex Media Server\Plug-ins
- tmp_dir = Core.storage.join_path(Core.app_support_path, "Cache")
- plugins_dir = Core.storage.join_path(Core.app_support_path, "Plug-ins", "")
- #Log("tmp_dir= "+tmp_dir)
-
- sources_directory = os.path.join(os.path.dirname(inspect.getsourcefile(content)), "sources")
- use_streams_file_remote = Prefs["general_use_streams_file_remote"]
- streams_file = Prefs["general_streams_file"]
- streams_file_remote = Prefs["general_streams_file_remote"]
-
- Log("[playstream] Create sources objects")
- if use_streams_file_remote:
- cfg_file = streams_file_remote
- cfg_file2 = streams_file
- else:
- cfg_file = streams_file
- cfg_file2 = None
- try:
- sources = ContentSources(sources_directory, cfg_file, cfg_file2)
- except Exception as e:
- Log(traceback.format_exc())
-
- cfg = sources.plugins["config"]
- Log("[playstream] Using streams_file=%s"% cfg.streams_file)
- ObjectContainer(header="Info", message="Using streams_file %s, reload plugin" % cfg.streams_file)
-
- data0 = None
- title0 = None
- history = []
-
- view_modes = {
- "List": 65586, "InfoList": 65592, "MediaPreview": 458803, "Showcase": 458810, "Coverflow": 65591,
- "PanelStream": 131124, "WallStream": 131125, "Songs": 65593, "Seasons": 65593, "Albums": 131123,
- "Episodes": 65590,"ImageStream":458809,"Pictures":131123
- }
- '''
- for source in sources.plugins:
- if not ("options" in dir(sources.plugins[source]) and sources.plugins[source].options): continue
- options = sources.plugins[source].options
- if not options: continue
- for option in options:
- key="%s_%s"%(source,option)
- if key in ("viaplay_device"): continue # exception list,
- value = plugin.get_setting(key)
- options[option] = value
- sources.plugins[source].options_write(options)
- prefix = ""
- '''
-
- ###################################################################################################
- def Start():
-
- ObjectContainer.title1 = CHANNEL_NAME
- ObjectContainer.art = R(ART)
- Plugin.AddViewGroup("InfoList", viewMode="InfoList", mediaType="items")
- Plugin.AddViewGroup("List", viewMode="List", mediaType="items")
-
- #DirectoryObject.thumb = R(ICON)
- #DirectoryObject.art = R(ART)
- #EpisodeObject.thumb = R(ICON)
- #EpisodeObject.art = R(ART)
- #VideoClipObject.thumb = R(ICON)
- #VideoClipObject.art = R(ART)
-
- #HTTP.CacheTime = CACHE_1DAY
- #HTTP.Headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
-
- def ValidatePrefs():
- #preferences = Prefs._sandbox.preferences.get()
- for source in sources.plugins:
- if not ("options" in dir(sources.plugins[source]) and sources.plugins[source].options): continue
- options = sources.plugins[source].options
- if not options: continue
- for option in options:
- key="%s_%s"%(source,option)
- if key in ("viaplay_device"): continue # exception list,
- value = Prefs[key]
- options[option] = value
- if not DEV:
- sources.plugins[source].options_write(options)
-
- if Prefs["general_use_streams_file_remote"]:
- cfg.set_streams_file(Prefs["general_streams_file_remote"])
- else:
- cfg.set_streams_file(Prefs["general_streams_file"])
-
- ####################################################################################################
- @handler(PREFIX, CHANNEL_NAME, art=ART, thumb=ICON)
- def Main():
-
- data = "config::home"
- oc = Menu(data, "Home")
- oc.view_group = "InfoList"
- ValidatePrefs()
- return oc
-
- ####################################################################################################
- @route(PREFIX+'/{data}/')
- def Menu2(data, title):
- return Menu(data, title)
-
- @route(PREFIX+'/search')
- def Search(query, data, title):
- #data = data.replace("%2F", "/")
- Log("Search data="+data)
- Log("Search query="+query)
- data2 = data.format(query)
- return Menu(data2, title)
-
-
-
- @route(PREFIX+'/{data}')
- def Menu(data, title, **kwargs):
- #includeBandwidths=1, checkFiles=0, includeConcerts=0, includeExtras=0, includeOnDeck=0, includePopularLeaves=1&includeChapters=1&checkFiles=1):
-
- global data0, title0, history
- #sources.plugins["config"].read_streams()
- Log("[playstream] ** Menu call: %s - %s" % ( data, title))
- if not data:
- data = u"config::home"
-
- # Process history
- #if data == "back":
- # data = history[-1][0].replace("/", "%2F") if history and history[-1][0] else "config::home"
- # title = history[-1][1] if history and history[-1][0] else "Home"
- #if data == data0 or (len(history) > 2 and data == history[-2]):
- # # fake call, skipped
- # Log("history skipped")
- #else:
- # if history and history[-1][0] and data == history[-1][0]:
- # history.pop()
- # Log("history poped")
- # else:
- # history.append((data0, title0))
- # Log("history added %s" % data0)
- #hst = ""
- #for h in history: hst += "\n%s" % h[0]
- #Log("[playstream] history="+hst)
- #
- #data0 = data
- #title0 = title
-
- data = data.replace("%2F", "/")
-
- ### Processig call ###
- Log("[playstream] processing data=%s"%data)
- try:
- is_video = sources.is_video(data)
- except:
- Log(traceback.format_exc())
- return ObjectContainer(header="Error", message=unicode(e))
-
- ### Video handling ###
- if is_video:
- try:
- streams = sources.get_streams(data)
- except Exception,e:
- Log(traceback.format_exc())
- return ObjectContainer(header="Error", message=unicode(e))
- if streams:
- data2 = data.replace("/", "%2F")
- title = streams[0]["name"] if isinstance(streams[0]["name"] , unicode) else streams[0]["name"].decode("utf8")
- if not title: title = "Title"
- desc = streams[0]["desc"] if isinstance(streams[0]["desc"] , unicode) else streams[0]["desc"] .decode("utf8")
- img = streams[0]["img"] if isinstance(streams[0]["img"] , unicode) else streams[0]["img"] .decode("utf8")
- vco = VideoClipObject(
- key=Callback(Menu, data=data2, title=title ),
- rating_key=data2,
- title=title,
- summary=desc,
- thumb=thumb_data(img, video=True)
- )
- for i, stream in enumerate(streams):
- headers = stream["headers"] if "headers" in stream and stream["headers"] else {"User-Agent":"Plex"}
- lang = stream["lang"] if "lang" in stream else "?"
- quality = stream["quality"] if "quality" in stream else "stream%s" % i
- resolution = "%s %s" % (lang, quality)
- if isinstance(resolution,str):
- resolution = resolution.decode("utf8")
- Log(resolution)
- height = "720" #"720"
- width = "1280" #"1280"
- vco.add(MediaObject(
- #bitrate=0,
- #container=Container.MPEGTS,
- video_resolution = resolution,
- height = height,
- width = width,
- optimized_for_streaming = True,
- parts=[PartObject(
- key=HTTPLiveStreamURL(stream["url"]),
- http_headers = headers
- )]
- ))
- include_container = True
- return ObjectContainer(objects = [vco]) if include_container else vco
- else:
- return ObjectContainer(header="Error", message="No streams found!")
-
-
- ### List handling ###
- oc = ObjectContainer(title2=title)
- oc.view_group = "InfoList"
- try:
- content = sources.get_content(data)
- except Exception,e:
- Log(traceback.format_exc())
- return ObjectContainer(header="Error", message=unicode(e))
- Log( "[playstream] %s items returned"%len(content))
-
- for item in content:
- if item[1] == "back": continue # nerādam back
- data2 = item[1]
- #data2 = urllib.quote(data2, safe="")
- data2 = data2.replace("/", "%2F")
- data2 = data2 if isinstance(data2, unicode) else data2.decode("utf8")
- title = item[0] if isinstance(item[0], unicode) else item[0].decode("utf8")
- if not title: title = "Title"
- img = item[2] #if isinstance(item[2], unicode) else item[2].decode("utf8")
- desc = item[3] if isinstance(item[3], unicode) else item[3].decode("utf8")
-
- # Search item #
- if "{0}" in data2:
- #q = "aaa" # TODO InputDirectoryObject
- ##data = data.format(q)
- #TODO problēma ar latviešu burtiem iekš DumbInput
- if Client.Product in DumbKeyboard.clients:
- DumbKeyboard(PREFIX, oc, Search,
- dktitle = title,
- dkthumb = thumb_data(SEARCH),
- title=title,
- data=data2
- )
- else:
- oc.add(InputDirectoryObject(
- key=Callback(Search, data=data2, title=title),
- title = title,
- thumb = thumb_data(img), #Resource.ContentsOfURLWithFallback(img, fallback=R(ICON)),
- prompt=desc,
- summary =desc
- ))
-
- # Video item #
- elif sources.is_video(item[1]):
- oc.add(VideoClipObject(
- key=Callback(Menu, data=data2, title=title),
- title = title,
- thumb = thumb_data(img, video=True), #Resource.ContentsOfURLWithFallback(img, fallback=R(ICON)),
- summary = desc,
- rating_key=data2
- ))
-
- # List object #
- else:
- oc.add(DirectoryObject(
- key=Callback(Menu, data=data2, title=title),
- title = title,
- thumb = thumb_data(img) if not data2=="back" else R(BACK),
- summary =desc
- ))
-
- if data == "config::home":
- if Client.Product in DumbPrefs.clients:
- DumbPrefs(PREFIX, oc,
- title = "Plugin options",
- thumb = R(PREFS))
- else:
- oc.add(PrefsObject(
- title="Plugin options",
- summary="Update plugin options",
- thumb=R(PREFS),
- art=R(ART)
- ))
- ValidatePrefs()
- version2 = get_repo_version()
- if version2 > VERSION:
- msg = "Update from %s to %s" % (VERSION, version2)
- else:
- msg = "Current version - %s" % (VERSION)
- oc.add(DirectoryObject(
- key=Callback(UpdateMenu),
- title = msg,
- thumb = R(UPDATE),
- summary ="Check whether update exist and offer to update"
- ))
-
- return oc
-
- #@route(PREFIX+'/updatemenu')
- def UpdateMenu():
- Log("UpdateMenu")
- version2 = get_repo_version()
- if version2 > VERSION:
- msg = "Current version - %s, new version available - %s" % (VERSION, version2)
- else:
- msg = "Current version - %s, no new version available" % (VERSION)
- oc = ObjectContainer(title1=msg, title2=msg, no_history=True)
- oc.add(DirectoryObject(key=Callback(UpdatePlugin, ver=version2), title="Update plugin", summary=msg, thumb = R(UPDATE)))
- return oc
-
- # @route(PREFIX+'/updateplugin')
- def UpdatePlugin(ver):
- Log("UpdatePlugin")
- Log("ver="+ver)
- if not ver:
- ver = get_repo_version()
- #return ObjectContainer(header="Error", message="ver=" % ver)
- fname = "PlayStream.bundle-%s.zip" % ver
- url = DOWNLOAD_URL + fname
- path = os.path.join(tmp_dir, fname)
- try:
- urllib.urlretrieve(url, path)
- with zipfile.ZipFile(path,"r") as zip_ref:
- zip_ref.extractall(plugins_dir)
- except:
- return ObjectContainer(header="Error", message="Can not download \n%s" % url)
- return ObjectContainer(header="Info", message="Plugin version updated to %s, reload plugin" % ver)
-
- def get_repo_version():
- try:
- r = requests.get(REPO_URL)
- if r.status_code <> 200:
- Log("[playstream] Can not reach repo")
- return ""
- vers = re.findall('href=".*PlayStream\.bundle-(\d+\.\d+\.\d+)\.zip"', r.content)
- #vers.sort(reverse=True)
- repo_version = vers[-1] if vers else 0
- return repo_version
- except:
- Log("[playstream] Can not reach repo")
- return ""
-
-
- def thumb_data(img, video=False):
- default = R(VIDEO) if video else R(FOLDER)
- if img.startswith('http'):
- img2 = Resource.ContentsOfURLWithFallback(img, default)
- elif img in ("default", ""):
- img2 = default
- else:
- img2 = R(img)
- return img2
|