summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYves Fischer <yvesf-git@xapek.org>2016-05-26 21:46:37 +0200
committerYves Fischer <yvesf-git@xapek.org>2016-05-26 21:46:37 +0200
commit3f55f3348788cbcbe2b47dfe0971b5e3ea5858af (patch)
tree73aacae83793735ea11617fabb902f4ee60bf3bc
parent8f0481fa1e3c54430ab79c0d1164c55b30c62049 (diff)
downloadflask-mediabrowser-3f55f3348788cbcbe2b47dfe0971b5e3ea5858af.tar.gz
flask-mediabrowser-3f55f3348788cbcbe2b47dfe0971b5e3ea5858af.zip
kodi plugin
-rw-r--r--kodi-mediabrowser/addon.xml17
-rw-r--r--kodi-mediabrowser/icon.pngbin0 -> 30799 bytes
-rw-r--r--kodi-mediabrowser/main.py62
-rw-r--r--kodi-mediabrowser/resources/settings.xml3
-rw-r--r--mediabrowser/__init__.py42
-rw-r--r--mediabrowser/ffmpeg.py2
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
new file mode 100644
index 0000000..f3cdd9e
--- /dev/null
+++ b/kodi-mediabrowser/icon.png
Binary files differ
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