diff options
author | JoeKer1 <jkerstanoff@callibrity.com> | 2017-01-31 12:01:38 -0500 |
---|---|---|
committer | Martijn Kaijser <martijn@xbmc.org> | 2017-01-31 18:01:38 +0100 |
commit | f10a463b52eaa953d8309d40dfc8c11154087b80 (patch) | |
tree | 7eeb8e02563b36aa704811e1d2b9d14a139d8363 /plugin.video.crossroads | |
parent | f2ad181639d89596645b0ced97e1f1ea4aeaeabb (diff) |
[plugin.video.crossroads] 1.0.0 (#932)
[plugin.video.crossroads] 1.0.0
Diffstat (limited to 'plugin.video.crossroads')
-rw-r--r-- | plugin.video.crossroads/.gitignore | 61 | ||||
-rw-r--r-- | plugin.video.crossroads/.vscode/tasks.json | 10 | ||||
-rw-r--r-- | plugin.video.crossroads/LICENSE | 29 | ||||
-rw-r--r-- | plugin.video.crossroads/README.md | 27 | ||||
-rw-r--r-- | plugin.video.crossroads/addon.xml | 45 | ||||
-rw-r--r-- | plugin.video.crossroads/fanart.jpg | bin | 0 -> 75917 bytes | |||
-rw-r--r-- | plugin.video.crossroads/icon.png | bin | 0 -> 25298 bytes | |||
-rw-r--r-- | plugin.video.crossroads/main.py | 280 | ||||
-rw-r--r-- | plugin.video.crossroads/resources/media/pastseries.png | bin | 0 -> 4340 bytes | |||
-rw-r--r-- | plugin.video.crossroads/resources/media/streaming.png | bin | 0 -> 8190 bytes | |||
-rw-r--r-- | plugin.video.crossroads/resources/screenshot-01.jpg | bin | 0 -> 55551 bytes | |||
-rw-r--r-- | plugin.video.crossroads/resources/screenshot-02.jpg | bin | 0 -> 97112 bytes | |||
-rw-r--r-- | plugin.video.crossroads/resources/screenshot-03.jpg | bin | 0 -> 63517 bytes |
13 files changed, 452 insertions, 0 deletions
diff --git a/plugin.video.crossroads/.gitignore b/plugin.video.crossroads/.gitignore new file mode 100644 index 0000000..1cc798f --- /dev/null +++ b/plugin.video.crossroads/.gitignore @@ -0,0 +1,61 @@ +# Created by .gitignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +#lib/ +#lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# PyCharm project files +.idea/ + +*.zip diff --git a/plugin.video.crossroads/.vscode/tasks.json b/plugin.video.crossroads/.vscode/tasks.json new file mode 100644 index 0000000..2ac4d86 --- /dev/null +++ b/plugin.video.crossroads/.vscode/tasks.json @@ -0,0 +1,10 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "Python", + "isShellCommand": true, + "args": ["${file}"], + "showOutput": "always", + "problemMatcher": "$tsc" +}
\ No newline at end of file diff --git a/plugin.video.crossroads/LICENSE b/plugin.video.crossroads/LICENSE new file mode 100644 index 0000000..d192c86 --- /dev/null +++ b/plugin.video.crossroads/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, Crossroads Church +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugin.video.crossroads/README.md b/plugin.video.crossroads/README.md new file mode 100644 index 0000000..7bc6305 --- /dev/null +++ b/plugin.video.crossroads/README.md @@ -0,0 +1,27 @@ +<!--# Simple example plugin for Kodi mediacenter + +This is a simple yet fully functional example of a video plugin for [Kodi](http://kodi.tv) mediacenter. +Please read the comments in the plugin code for more details. +An installable .zip can be downloaded from "[Releases](https://github.com/romanvm/plugin.video.example/releases)" tab. + +**Note**: the purpose of this example plugin is to show you how to organize and play your media content in Kodi. +The methods of obtaining such content, for example parsing websites or working with various APIs, +are beyond the scope of this example. + +The plugin uses a pre-defined set of free sample videos from [www.vidsplay.com](http://www.vidsplay.com/). + +**Warning**: the "master" branch is only compatible with Kody 16.0 (Jarvis) and above. For older versions see the "legacy" branch. + +License: [GPL v.3](http://www.gnu.org/copyleft/gpl.html)--> + +# Crossroads Church streaming addon + +This addon provides access to past Crossroads messages and a live stream of the current broadcast if available. + +#About Crossroads +Crossroads is based in Oakley, Ohio with sites around the Cincinnati and Central KY (Lexington) areas. If you're not located near those areas checkout [Crossroads Anywhere](https://www.crossroads.net/live) +Crossroads is for anyone who wants to seek God-from those exploring whether or not God even exists, to committed Christ-followers. +We present biblical truths and show how they apply to our everyday lives. And we have a lot of fun while doing it. + +For the longer answer, check out [our history](https://www.crossroads.net/ourhistory), [manifesto](https://www.crossroads.net/manifesto), [what we believe](https://www.crossroads.net/whatwebelieve), [the seven hills we die on](https://www.crossroads.net/sevenhills) or [the FAQ](https://www.crossroads.net/frequentquestions). + diff --git a/plugin.video.crossroads/addon.xml b/plugin.video.crossroads/addon.xml new file mode 100644 index 0000000..18985e8 --- /dev/null +++ b/plugin.video.crossroads/addon.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="plugin.video.crossroads" +version="1.0.0" +name="Crossroads Church" +provider-name="CRDS"> +<requires> + <import addon="xbmc.python" version="2.25.0"/> + <import addon="script.module.urlresolver" version="2.10.0" /> + <import addon="script.module.metahandler" version="1.0.0" /> + <import addon="script.module.requests" version="2.7.0" /> + <import addon="plugin.video.youtube" version="5.3.6"/> + <import addon="script.common.plugin.cache" version="2.5.8"/> +</requires> +<extension point="xbmc.python.pluginsource" library="main.py"> + <provides>video</provides> +</extension> +<extension point="xbmc.addon.metadata"> + <summary lang="en">Crossroads Church</summary> + <description lang="en">This plugin provides access to live crossroads streams and past services. +We started this church for our friends who didn't like church. +Crossroads is for anyone who wants to seek God-from those exploring whether or not God even exists, to committed Christ-followers. +We present biblical truths and show how they apply to our everyday lives. And we have a lot of fun while doing it.</description> + <disclaimer lang="en">This addon is supported by crds volunteers</disclaimer> + <license>BSD 3-Clause License</license> + <website>https://www.crossroads.net</website> + <email>support@crossroads.net</email> + <source>https://github.com/crdschurch/plugin.video.crossroads</source> + <platform>all</platform> + <language>en</language> + <assets> + <icon>icon.png</icon> + <fanart>fanart.jpg</fanart> + <icon>resources\media\pastseries.png</icon> + <icon>resources\media\streaming.png</icon> + <screenshot>resources\screenshot-01.jpg</screenshot> + <screenshot>resources\screenshot-02.jpg</screenshot> + <screenshot>resources\screenshot-03.jpg</screenshot> + </assets> + <news>v1.0.0 (2017-1-27) +- First version of Crossroads Stream Addon! +- Added ability to stream live service if there is a stream active +- Added ability to watch previous services + </news> +</extension> +</addon> diff --git a/plugin.video.crossroads/fanart.jpg b/plugin.video.crossroads/fanart.jpg Binary files differnew file mode 100644 index 0000000..fcaf8b8 --- /dev/null +++ b/plugin.video.crossroads/fanart.jpg diff --git a/plugin.video.crossroads/icon.png b/plugin.video.crossroads/icon.png Binary files differnew file mode 100644 index 0000000..9ba1110 --- /dev/null +++ b/plugin.video.crossroads/icon.png diff --git a/plugin.video.crossroads/main.py b/plugin.video.crossroads/main.py new file mode 100644 index 0000000..326cd92 --- /dev/null +++ b/plugin.video.crossroads/main.py @@ -0,0 +1,280 @@ +# -*- coding: utf-8 -*- +# Module: default +# Author: Doug Shannon, Chris Andrews, and Joe Kerstanoff based off sample plugin by Roman V. M. +# Created on: 26.1.2017 +# License: GPL v.3 https://www.gnu.org/copyleft/gpl.html + +import sys +from urllib import urlencode +from urlparse import parse_qsl +import xbmc +import xbmcgui +import xbmcplugin +import os +import urlresolver +import requests +import re +import ast + +# imports caching to SQLite cache database for function calls +try: + import StorageServer +except: + import storageserverdummy as StorageServer +cache = StorageServer.StorageServer("crossroads", 1) + +# Streamspot +_streamspot_url = 'https://api.streamspot.com/' +_streamspot_api_key = '82437b4d-4e38-42e2-83b6-148fcfaf36fb' +_streamspot_ssid = 'crossr4915' +_streamspot_header = { + "Content-Type": 'application/json', + "x-API-Key": _streamspot_api_key +} +_streamspot_player = '2887fba1' +# Get the plugin url in plugin:// notation. +_url = sys.argv[0] +# Get the plugin handle as an integer number. +_handle = int(sys.argv[1]) + +def remove_non_ascii(text): + """ + Removes non Ascii characters from a string + """ + return ''.join([i if ord(i) < 128 else '' for i in text]) + +def cleanhtml(raw_html): + """ + Turns HTML contents into just their strings + """ + cleanr = re.compile('<.*?>') + cleantext = re.sub(cleanr, '', raw_html) + return cleantext + + +def get_url(**kwargs): + """ + Create a URL for calling the plugin recursively from the given set of keyword arguments. + + :param kwargs: "argument=value" pairs + :type kwargs: dict + :return: plugin call URL + :rtype: str + """ + return '{0}?{1}'.format(_url, urlencode(kwargs)) + + +def get_categories(): + """ + Get the list of video series. + .. note:: Consider using `generator functions <https://wiki.python.org/moin/Generators>`_ + instead of returning lists. + + :return: The list of video categories + :rtype: list + """ + + resp = requests.get('https://www.crossroads.net/proxy/content/api/series') + data = resp.json()['series'] + data = filter(filter_series_with_no_videos, data) + return data + +def get_broadcaster(): + resp = requests.get('{}broadcaster/{}?players=true'.format(_streamspot_url, _streamspot_ssid), headers=_streamspot_header) + return resp.json()['data']['broadcaster'] + +def get_broadcaster_stream_link(broadcaster): + return broadcaster['live_src']['hls'] + +def filter_series_with_no_videos(series): + """ + Filter out series that do not have any playable media + """ + for event in series['messages']: + if 'messageVideo' in event and event['messageVideo']['serviceId'] is not None: + return True + else: + return False + +def show_main_menu(): + """ + Create the initial interface for past or live series. + """ + broadcaster = get_broadcaster() + liveicon = os.path.join(os.path.dirname(__file__), 'resources', 'media', 'streaming.png') + pastseries = os.path.join(os.path.dirname(__file__), 'resources', 'media', 'pastseries.png') + fanart = os.path.join(os.path.dirname(__file__), 'fanart.jpg') + + if broadcaster['isBroadcasting']: + # Live + list_item_live = xbmcgui.ListItem(label='Watch live stream now') + list_item_live.setInfo('video', {'title': 'Watch live stream now', 'plot': """Live Streams: +SAT 4:30 & 6:15pm +SUN 8:30, 10:05 & 11:55am (EST)"""}) + list_item_live.setArt({'thumb': liveicon, + 'icon': liveicon, + 'fanart': fanart}) + url_live = get_url(action='play', video=get_broadcaster_stream_link(broadcaster)) + xbmcplugin.addDirectoryItem(_handle, url_live, list_item_live, False) + + # Historical + list_item_past = xbmcgui.ListItem(label='Past Series') + list_item_past.setInfo('video', {'title': 'Past Series', 'plot': 'Watch our previous weekend messages'}) + list_item_past.setArt({'thumb': pastseries, + 'icon': pastseries, + 'fanart': fanart}) + + url_past = get_url(action='historical') + xbmcplugin.addDirectoryItem(_handle, url_past, list_item_past, True) + xbmcplugin.endOfDirectory(_handle) + + +def list_categories(): + """ + Create the list of video categories in the Kodi interface. + """ + # Get video categories + categories = cache.cacheFunction(get_categories) + # Iterate through categories + for category in categories: + # Create a list item with a text label and a thumbnail image. + list_item = xbmcgui.ListItem(label=category['startDate'][5:] + ' ' + category['title']) + # Set graphics (thumbnail, fanart, banner, poster, landscape etc.) for the list item. + list_item.setArt({'thumb': category['image']['filename'], + 'icon': category['image']['filename'], + 'fanart': category['image']['filename']}) + # Set additional info for the list item. + # http://mirrors.xbmc.org/docs/python-docs/15.x-isengard/xbmcgui.html#ListItem-setInfo + + list_item.setInfo('video', + {'title': category['title'], + 'trailer': category['trailerLink'], + 'plot': cleanhtml(category['description']), + 'dateadded': category['startDate'], + 'year': category['startDate'][:4]}) + # Create a URL for a plugin recursive call. + # Example: + # plugin://plugin.video.example/?action=listing&category=Animals + url = get_url(action='listing', series=category) + # is_folder = True means that this item opens a sub-list of lower level + is_folder = True + # Add context Menu Option for trailer if it exists + if category['trailerLink'] != None: + traileurl = urlresolver.resolve(category['trailerLink']) + list_item.addContextMenuItems([('Play Trailer', 'PlayMedia(' + traileurl + ')')]) + # Add our item to the Kodi virtual folder listing. + xbmcplugin.addDirectoryItem(_handle, url, list_item, is_folder) + # Add a sort method for the virtual folder items (alphabetically, ignore + # articles) + #xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) + # Finish creating a virtual folder. + xbmcplugin.endOfDirectory(_handle) + + +def list_videos(series): + """ + Create the list of playable videos in the Kodi interface. + :param messages: Array of messages + :type messages: json + """ + series = ast.literal_eval(cleanhtml(series).replace('u\'', '\'')) + + # Iterate through videos. + for message in series['messages']: + # Create a list item with a text label and a thumbnail image. + list_item = xbmcgui.ListItem(label=message['title']) + # Set additional info for the list item. + list_item.setInfo('video', + {'title': message['date'][5:] + ' ' + message['title'], + 'genre': 'message', 'plot': message['description'], + 'premiered': message.get('date', ""), + 'dateadded': message.get('date', "")}) + # Set graphics (thumbnail, fanart, banner, poster, landscape etc.) for the list item. + if 'messageVideo' in message and 'still' in message['messageVideo']: + imagesrc = message['messageVideo']['still']['filename'] + else: + imagesrc = series['image']['filename'] + + list_item.setArt({'thumb': imagesrc, + 'icon': imagesrc, + 'fanart': series['image']['filename']}) + # Set 'IsPlayable' property to 'true'. + # This is mandatory for playable items! + list_item.setProperty('IsPlayable', 'true') + # Create a URL for a plugin recursive call. + # Example: + # plugin://plugin.video.example/?action=play&video=http://www.vidsplay.com/vids/crab.mp4 + if 'messageVideo' in message and 'serviceId' in message['messageVideo']: + vidurl = message['messageVideo']['serviceId'] + else: + vidurl = "" + + url = get_url(action='play', + video="{}{}".format("https://www.youtube.com/watch?v=", + vidurl)) + # Add the list item to a virtual Kodi folder. + # is_folder = False means that this item won't open any sub-list. + is_folder = False + # Add our item to the Kodi virtual folder listing. + xbmcplugin.addDirectoryItem(_handle, url, list_item, is_folder) + # Add a sort method for the virtual folder items (alphabetically, ignore + # articles) + xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_DATEADDED) + # Finish creating a virtual folder. + xbmcplugin.endOfDirectory(_handle) + +def play_video(path): + """ + Play a video by the provided path. + + :param path: Fully-qualified video URL + :type path: str + """ + + if path[-4:] == 'm3u8': + xbmc.Player().play(path) + else: + # Create a playable item with a path to play. + play_item = xbmcgui.ListItem(path=urlresolver.resolve(path)) + # Pass the item to the Kodi player. + xbmcplugin.setResolvedUrl(_handle, True, listitem=play_item) + + +def router(paramstring): + """ + Router function that calls other functions + depending on the provided paramstring + + :param paramstring: URL encoded plugin paramstring + :type paramstring: str + """ + + # Parse a URL-encoded paramstring to the dictionary of + # {<parameter>: <value>} elements + params = dict(parse_qsl(paramstring)) + # Check the parameters passed to the plugin + if params: + if params['action'] == 'listing': + # Display the list of videos in a provided series. + list_videos(params['series']) + elif params['action'] == 'play': + # Play a video from a provided URL. + play_video(params['video']) + elif params['action'] == 'historical': + list_categories() + else: + # If the provided paramstring does not contain a supported action + # we raise an exception. This helps to catch coding errors, + # e.g. typos in action names. + raise ValueError('Invalid paramstring: {0}!'.format(paramstring)) + else: + # If the plugin is called from Kodi UI without any parameters, + # display the list of video categories + show_main_menu() + + +if __name__ == '__main__': + # Call the router function and pass the plugin call parameters to it. + # We use string slicing to trim the leading '?' from the plugin call + # paramstring + router(sys.argv[2][1:]) diff --git a/plugin.video.crossroads/resources/media/pastseries.png b/plugin.video.crossroads/resources/media/pastseries.png Binary files differnew file mode 100644 index 0000000..083ca65 --- /dev/null +++ b/plugin.video.crossroads/resources/media/pastseries.png diff --git a/plugin.video.crossroads/resources/media/streaming.png b/plugin.video.crossroads/resources/media/streaming.png Binary files differnew file mode 100644 index 0000000..30a9ea3 --- /dev/null +++ b/plugin.video.crossroads/resources/media/streaming.png diff --git a/plugin.video.crossroads/resources/screenshot-01.jpg b/plugin.video.crossroads/resources/screenshot-01.jpg Binary files differnew file mode 100644 index 0000000..a80ee51 --- /dev/null +++ b/plugin.video.crossroads/resources/screenshot-01.jpg diff --git a/plugin.video.crossroads/resources/screenshot-02.jpg b/plugin.video.crossroads/resources/screenshot-02.jpg Binary files differnew file mode 100644 index 0000000..6debdf1 --- /dev/null +++ b/plugin.video.crossroads/resources/screenshot-02.jpg diff --git a/plugin.video.crossroads/resources/screenshot-03.jpg b/plugin.video.crossroads/resources/screenshot-03.jpg Binary files differnew file mode 100644 index 0000000..393eca8 --- /dev/null +++ b/plugin.video.crossroads/resources/screenshot-03.jpg |