Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugin.video.opentakserver] 1.0.0 #4606

Merged
merged 1 commit into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
619 changes: 619 additions & 0 deletions plugin.video.opentakserver/LICENSE.txt

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions plugin.video.opentakserver/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# OpenTAKServer Kodi Plugin

A simple plugin that allows you to watch live streams and recordings from your [OpenTAKServer](https://github.com/brian7704/OpenTAKServer) in [Kodi](https://kodi.tv).
164 changes: 164 additions & 0 deletions plugin.video.opentakserver/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import datetime
import os
import sys
import uuid
from urllib.parse import urlencode, parse_qsl
import requests

import xbmc
import xbmcgui
import xbmcplugin
import xbmcvfs
import xbmcaddon
from xbmcaddon import Addon
from xbmcvfs import translatePath

# Get the plugin url in plugin:// notation.
URL = sys.argv[0]
# Get a plugin handle as an integer number.
HANDLE = int(sys.argv[1])
# Get addon base path
ADDON_PATH = translatePath(Addon().getAddonInfo('path'))
ICONS_DIR = os.path.join(ADDON_PATH, 'resources', 'images', 'icons')
FANART_DIR = os.path.join(ADDON_PATH, 'resources', 'images', 'fanart')
__addon__ = xbmcaddon.Addon(id='plugin.video.opentakserver')
__addondir__ = xbmcvfs.translatePath( __addon__.getAddonInfo('profile'))

csrf_token = None


def get_auth_token_from_file():
f = xbmcvfs.File(os.path.join(__addondir__, "auth_token"), 'r')
auth_token = f.read()
f.close()
return auth_token


def get(url):
auth_token = get_auth_token_from_file()

r = requests.get(url, params={'auth_token': auth_token}, verify=bool(xbmcplugin.getSetting(HANDLE, "verify_certificates")))
if r.status_code != 200:
xbmc.log(f"Failed to get {url}: {r.text}", xbmc.LOGERROR)
return r


def login():
r = requests.post(xbmcplugin.getSetting(HANDLE, "server_url") + "/api/login?include_auth_token",
json={'username': xbmcplugin.getSetting(HANDLE, "username"),
'password': xbmcplugin.getSetting(HANDLE, "password")})
if r.status_code == 200:
auth_token = r.json()['response']['user']['authentication_token']
xbmc.log(f"login() {auth_token}", xbmc.LOGINFO)
f = xbmcvfs.File(os.path.join(__addondir__, 'auth_token'), 'w')
f.write(auth_token)
f.close()
else:
dialog = xbmcgui.Dialog()
dialog.notification('Login Failed', 'Check the settings and try again', xbmcgui.NOTIFICATION_INFO, 5000)


def format_url(**kwargs):
"""
Create a URL for calling the plugin recursively from the given set of keyword arguments.

:param kwargs: "argument=value" pairs
:return: plugin call URL
:rtype: str
"""
return '{}?{}'.format(URL, urlencode(kwargs))


def router(paramstring):
"""
Router function that calls other functions
depending on the provided paramstring

:param paramstring: URL encoded plugin paramstring
:type paramstring: str
"""
params = dict(parse_qsl(paramstring))
xbmc.log("paramstring " + str(paramstring), xbmc.LOGINFO)
xbmcplugin.setPluginCategory(HANDLE, "OpenTAKServer")
xbmcplugin.setContent(HANDLE, 'videos')
auth_token = get_auth_token_from_file()

window = xbmcgui.Window(10000)

# Check the parameters passed to the plugin
if not params:
login()
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="streams", page="1"), xbmcgui.ListItem(label="Streams"), True)
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="recordings", page="1"), xbmcgui.ListItem(label="Recordings"), True)
xbmcplugin.endOfDirectory(HANDLE)

elif params['choice'] == "streams":
page = params["page"]
if not page:
page = 1
else:
page = int(page)

if page > 1:
list_item = xbmcgui.ListItem(label="Previous Page")
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="streams", page=str(page - 1)), list_item, isFolder=True)

streams = get(xbmcplugin.getSetting(HANDLE, "server_url") + "/api/video_streams").json()
for stream in streams['results']:
list_item = xbmcgui.ListItem(label=stream['path'])

# The random UUID prevents Kodi from pulling the thumbnail from cache. The server ignores it
thumbnail = xbmcplugin.getSetting(HANDLE, "server_url") + '/api/videos/thumbnail?path={}&random={}&auth_token={} '.format(stream['path'], str(uuid.uuid4()), auth_token)
list_item.setArt({'thumb': thumbnail, 'fanart': thumbnail})

xbmcplugin.addDirectoryItem(HANDLE, f"{stream['rtsp_link']}?jwt={auth_token}", list_item, False)

if page < streams['total_pages']:
list_item = xbmcgui.ListItem(label="Next Page")
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="streams", page=str(page + 1)), list_item, isFolder=True)
xbmcplugin.endOfDirectory(HANDLE)

elif params['choice'] == 'recordings':
page = params["page"]
if not page:
page = 1
else:
page = int(page)

if page > 1:
list_item = xbmcgui.ListItem(label="Previous Page")
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="recordings", page=str(page - 1)), list_item, isFolder=True)

server_url = xbmcplugin.getSetting(HANDLE, "server_url")
recordings = get("{}/api/videos/recordings?page={}".format(server_url, page))
xbmc.log(recordings.text, xbmc.LOGINFO)
for recording in recordings.json()['results']:
url = "{}/api/videos/recording?id={}&auth_token={}|Cookie=Cookie: ".format(server_url, recording['id'], auth_token)
thumbnail = '{}/api/videos/thumbnail?path={}&recording={}&random={}&auth_token={}'.format(server_url, recording['path'], recording['filename'], str(uuid.uuid4()), auth_token)
list_item = xbmcgui.ListItem(label=recording['path'] + " - " + recording['start_time'])
list_item.setArt({'thumb': thumbnail})
try:
start_time = datetime.datetime.strptime(recording['start_time'], "%Y-%m-%dT%H:%M:%SZ")
except:
start_time = datetime.datetime.now()

tag = list_item.getVideoInfoTag()
tag.setDateAdded(start_time.strftime("%Y-%m-%d %H:%M:%S"))
tag.setPremiered(start_time.strftime("%Y-%m-%d %H:%M:%S"))
if recording['duration']:
tag.setDuration(recording['duration'])
xbmcplugin.addDirectoryItem(HANDLE, url, list_item)

if page < recordings.json()['total_pages']:
list_item = xbmcgui.ListItem(label="Next Page")
xbmcplugin.addDirectoryItem(HANDLE, format_url(choice="recordings", page=str(page + 1)), list_item, isFolder=True)

xbmcplugin.endOfDirectory(HANDLE)
else:
raise ValueError(f'Invalid paramstring: {paramstring}!')


if __name__ == '__main__':
if not xbmcplugin.getSetting(HANDLE, "server_url") or not xbmcplugin.getSetting(HANDLE, "username") or not xbmcplugin.getSetting(HANDLE, "password"):
xbmcaddon.Addon().openSettings()
router(sys.argv[2][1:])
25 changes: 25 additions & 0 deletions plugin.video.opentakserver/addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon id="plugin.video.opentakserver"
version="1.0.0"
name="OpenTAKServer Video Plugin"
provider-name="OpenTAKServer">
<requires>
<import addon="xbmc.python" version="3.0.1"/>
<import addon="script.module.requests" version="2.31.0"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">OpenTAKServer Video Plugin</summary>
<description lang="en_GB">View your OpenTAKServer video streams and recordings in Kodi</description>
<license>GPL-3.0-only</license>
<language>en</language>
<website>https://docs.opentakserver.io</website>
<source>https://github.com/brian7704/OpenTAKServer-Kodi</source>
<email>[email protected]</email>
<assets>
<icon>resources/images/ots-logo.png</icon>
</assets>
</extension>
</addon>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions plugin.video.opentakserver/resources/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
<category label="32001">
<setting label="Username" type="text" id="username" default="" />
<setting label="Password" type="text" id="password" option="hidden" enable="!eq(-1,)" default="" />
<setting label="Server URL" type="text" id="server_url" default="https://public.opentakserver.io" />
<setting label="Verify HTTPS Certificates" type="bool" id="verify_certificates" default="false" />
</category>
</settings>
Loading