diff options
-rw-r--r-- | kodi-mediabrowser/addon.xml | 17 | ||||
-rw-r--r-- | kodi-mediabrowser/icon.png | bin | 0 -> 30799 bytes | |||
-rw-r--r-- | kodi-mediabrowser/main.py | 62 | ||||
-rw-r--r-- | kodi-mediabrowser/resources/settings.xml | 3 | ||||
-rw-r--r-- | mediabrowser/__init__.py | 42 | ||||
-rw-r--r-- | mediabrowser/ffmpeg.py | 2 |
6 files changed, 123 insertions, 3 deletions
diff --git a/kodi-mediabrowser/addon.xml b/kodi-mediabrowser/addon.xml new file mode 100644 index 0000000..4343427 --- /dev/null +++ b/kodi-mediabrowser/addon.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<addon id="plugin.video.kodiMediabrowser" + version="0.0.1" + name="Kodi Mediabrowser" + provider-name="yvesf"> + <requires> + <import addon="xbmc.python" version="2.24.0"/> + </requires> + <extension point="xbmc.python.pluginsource" library="main.py"> + <provides>video</provides> + </extension> + <extension point="xbmc.addon.metadata"> + <summary lang="en">Kodi plugin for flask-mediabrowser</summary> + <description lang="en">Allows to browse videos from kodi.</description> + <disclaimer lang="en">...</disclaimer> + </extension> +</addon> diff --git a/kodi-mediabrowser/icon.png b/kodi-mediabrowser/icon.png Binary files differnew file mode 100644 index 0000000..f3cdd9e --- /dev/null +++ b/kodi-mediabrowser/icon.png diff --git a/kodi-mediabrowser/main.py b/kodi-mediabrowser/main.py new file mode 100644 index 0000000..ad70506 --- /dev/null +++ b/kodi-mediabrowser/main.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Module: default +import sys +from urlparse import parse_qsl +import xbmcgui +import xbmcplugin +import xbmcaddon +import requests +from urllib import quote +import logging + +logging.basicConfig(level=logging.INFO) + +# Get the plugin url in plugin:// notation. +_url = sys.argv[0] +# Get the plugin handle as an integer number. +_handle = int(sys.argv[1]) + +addon = xbmcaddon.Addon() + +endpoint = addon.getSetting('endpoint') + + +def list_files(path): + resp = requests.get(endpoint + path) + data = resp.json() + files = data['files'] + + listing = [] + for file in files: + list_item = xbmcgui.ListItem(label=file['name']) + + if file['type'] == 'directory': + list_item.setInfo('video', {'title': file['name'] + '/'}) + url = '{0}?action=list_files&path={1}'.format(_url, quote(file['path'])) + listing.append((url, list_item, True)) + else: + list_item.setInfo('video', {'title': file['name']}) + list_item.setArt({'thumb': endpoint + file['poster']}) + list_item.setProperty('IsPlayable', 'true') + url = endpoint + file['m3u8'] + listing.append((url, list_item, False)) + xbmcplugin.addDirectoryItems(_handle, listing, len(listing)) + xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) + xbmcplugin.endOfDirectory(_handle) + + +def router(paramstring): + params = dict(parse_qsl(paramstring)) + if params: + if params['action'] == 'list_files': + # Display the list of videos in a provided category. + list_videos(params['path']) + else: + raise Exception('Invalid params') + else: + list_files('/json/') + + +if __name__ == '__main__': + router(sys.argv[2][1:]) diff --git a/kodi-mediabrowser/resources/settings.xml b/kodi-mediabrowser/resources/settings.xml new file mode 100644 index 0000000..af2b4e2 --- /dev/null +++ b/kodi-mediabrowser/resources/settings.xml @@ -0,0 +1,3 @@ +<settings> + <setting id="endpoint" type="text" label="Server endpoint" default="http://localhost:8000"/> +</settings>
\ No newline at end of file diff --git a/mediabrowser/__init__.py b/mediabrowser/__init__.py index 28241b4..5faed84 100644 --- a/mediabrowser/__init__.py +++ b/mediabrowser/__init__.py @@ -6,7 +6,7 @@ from datetime import datetime from functools import partial from flask import Blueprint, render_template, abort, \ - url_for, Response, request + url_for, Response, request, jsonify from . import ffmpeg @@ -37,11 +37,14 @@ class cached(object): return wrapped_func + class cached_stream(object): """decorator to apply SavingIoWrapper""" + def __init__(self, cache, keyfunc): self.cache = cache self.keyfunc = keyfunc + def __call__(self, func): def wrapped_func(*args, **kwargs): key = self.keyfunc(*args, **kwargs) @@ -58,6 +61,7 @@ class cached_stream(object): class SavingIoWrapper(io.RawIOBase): """Wraps a read-only io stream and buffers all read-ed data. on close() that data is written to the specified cache""" + def __init__(self, stream, key, cache): self.stream = stream self.key = key @@ -165,7 +169,7 @@ def build(root_directory, cache): new_t_prev_duration, new_t = ffmpeg.find_next_keyframe(ospath, ss + t, t / 2) new_t -= new_ss # minus one frame - new_t -= new_t_prev_duration + # new_t -= new_t_prev_duration process = ffmpeg.stream(ospath, new_ss, new_t) return Response(process.stdout, mimetype='video/MP2T') @@ -277,4 +281,38 @@ def build(root_directory, cache): except FileNotFoundError: abort(404) + @blueprint.route('/json/', defaults={'path': ''}) + @blueprint.route('/json/<path:path>') + def json(path): + def gather_fileinfo(path, ospath, filename): + osfilepath = os.path.join(ospath, filename) + if os.path.isdir(osfilepath) and not filename.startswith('.'): + return {'type': 'directory', + 'name': filename, + 'path': url_for('mediabrowser.json', + path=os.path.join(path, filename))} + else: + if not get_video_mime_type(osfilepath): + return None + else: + return {'type': 'file', + 'name': filename, + 'download': url_for('mediabrowser.download', + path=os.path.join(path, filename)), + 'poster': url_for('mediabrowser.poster', + path=os.path.join(path, filename)), + 'trailer': url_for('mediabrowser.thumbnail_video', + path=os.path.join(path, filename)), + 'm3u8': url_for('mediabrowser.m3u8', + path=os.path.join(path, filename))} + + try: + path = os.path.normpath(path) + ospath = os.path.join(root_directory, path) + files = list( + map(partial(gather_fileinfo, path, ospath), os.listdir(ospath))) + return jsonify({'files': files}) + except FileNotFoundError: + abort(404) + return blueprint diff --git a/mediabrowser/ffmpeg.py b/mediabrowser/ffmpeg.py index d4ad699..dfdc619 100644 --- a/mediabrowser/ffmpeg.py +++ b/mediabrowser/ffmpeg.py @@ -41,7 +41,7 @@ def stream(ospath, ss, t): shlex.split("-c:a aac -strict experimental -ac 2 -b:a 64k" " -c:v libx264 -pix_fmt yuv420p -profile:v high -level 4.0 -preset ultrafast -trellis 0" " -crf 31 -vf scale=w=trunc(oh*a/2)*2:h=480" - " -f mpegts" + " -shortest -f mpegts" " -output_ts_offset {output_ts_offset:.6f} -t {t:.6f} pipe:%d.ts".format(**locals())), stdout=PIPE) return cutter |