summaryrefslogtreecommitdiff
path: root/plugin.video.crossroads
diff options
context:
space:
mode:
authorJoeKer1 <jkerstanoff@callibrity.com>2017-01-31 12:01:38 -0500
committerMartijn Kaijser <martijn@xbmc.org>2017-01-31 18:01:38 +0100
commitf10a463b52eaa953d8309d40dfc8c11154087b80 (patch)
tree7eeb8e02563b36aa704811e1d2b9d14a139d8363 /plugin.video.crossroads
parentf2ad181639d89596645b0ced97e1f1ea4aeaeabb (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/.gitignore61
-rw-r--r--plugin.video.crossroads/.vscode/tasks.json10
-rw-r--r--plugin.video.crossroads/LICENSE29
-rw-r--r--plugin.video.crossroads/README.md27
-rw-r--r--plugin.video.crossroads/addon.xml45
-rw-r--r--plugin.video.crossroads/fanart.jpgbin0 -> 75917 bytes
-rw-r--r--plugin.video.crossroads/icon.pngbin0 -> 25298 bytes
-rw-r--r--plugin.video.crossroads/main.py280
-rw-r--r--plugin.video.crossroads/resources/media/pastseries.pngbin0 -> 4340 bytes
-rw-r--r--plugin.video.crossroads/resources/media/streaming.pngbin0 -> 8190 bytes
-rw-r--r--plugin.video.crossroads/resources/screenshot-01.jpgbin0 -> 55551 bytes
-rw-r--r--plugin.video.crossroads/resources/screenshot-02.jpgbin0 -> 97112 bytes
-rw-r--r--plugin.video.crossroads/resources/screenshot-03.jpgbin0 -> 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
new file mode 100644
index 0000000..fcaf8b8
--- /dev/null
+++ b/plugin.video.crossroads/fanart.jpg
Binary files differ
diff --git a/plugin.video.crossroads/icon.png b/plugin.video.crossroads/icon.png
new file mode 100644
index 0000000..9ba1110
--- /dev/null
+++ b/plugin.video.crossroads/icon.png
Binary files differ
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
new file mode 100644
index 0000000..083ca65
--- /dev/null
+++ b/plugin.video.crossroads/resources/media/pastseries.png
Binary files differ
diff --git a/plugin.video.crossroads/resources/media/streaming.png b/plugin.video.crossroads/resources/media/streaming.png
new file mode 100644
index 0000000..30a9ea3
--- /dev/null
+++ b/plugin.video.crossroads/resources/media/streaming.png
Binary files differ
diff --git a/plugin.video.crossroads/resources/screenshot-01.jpg b/plugin.video.crossroads/resources/screenshot-01.jpg
new file mode 100644
index 0000000..a80ee51
--- /dev/null
+++ b/plugin.video.crossroads/resources/screenshot-01.jpg
Binary files differ
diff --git a/plugin.video.crossroads/resources/screenshot-02.jpg b/plugin.video.crossroads/resources/screenshot-02.jpg
new file mode 100644
index 0000000..6debdf1
--- /dev/null
+++ b/plugin.video.crossroads/resources/screenshot-02.jpg
Binary files differ
diff --git a/plugin.video.crossroads/resources/screenshot-03.jpg b/plugin.video.crossroads/resources/screenshot-03.jpg
new file mode 100644
index 0000000..393eca8
--- /dev/null
+++ b/plugin.video.crossroads/resources/screenshot-03.jpg
Binary files differ