-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b927552
Showing
14 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/.idea | ||
/build | ||
/*.egg-info | ||
/.pytest_cache | ||
__pycache__ | ||
/venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
|
||
SOURCES=$(shell find . -name *.py) | ||
OUTPUT_PATH=build/plugin.video.ipfs | ||
|
||
venv: | ||
( \ | ||
virtualenv --python=python3.7 venv | ||
source venv/bin/activate; \ | ||
pip install -r requirements.txt; \ | ||
) | ||
|
||
test: install venv $(SOURCES) | ||
venv/bin/py.test | ||
|
||
install: | ||
venv/bin/python setup.py develop | ||
|
||
clean: | ||
rm -rf build | ||
|
||
build/plugin_video_ipfs.zip: build | ||
cd build && zip -r plugin_video_ipfs.zip plugin.video.ipfs | ||
|
||
build: $(SOURCES) fanart.jpg icon.png addon.xml | ||
mkdir -p $(OUTPUT_PATH)/ipfs | ||
cp -r src/*.py $(OUTPUT_PATH) | ||
cp -r src/ipfs/*.py $(OUTPUT_PATH)/ipfs | ||
cp -r resources $(OUTPUT_PATH) | ||
cp icon.png $(OUTPUT_PATH) | ||
cp addon.xml $(OUTPUT_PATH) | ||
cp fanart.jpg $(OUTPUT_PATH) | ||
|
||
package: build/plugin_video_ipfs.zip | ||
unzip -t build/plugin_video_ipfs.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# IPFS video plugin for Kodi | ||
|
||
Plugin to browse and play video media from IPFS. | ||
|
||
It has a configurable gateway and a configurable root CID that you can browse. | ||
|
||
# Build from source | ||
|
||
- `make package` | ||
- Copy the `build/plugin_video_ipfs.zip` | ||
|
||
# Viewing your own content | ||
|
||
- Install IPFS on your media player | ||
- Use `ipfs add -r -w yourdirectory` to insert your directory | ||
- Configure plugin to have gateway point to `http://localhost:8080` | ||
- Use the hash of the directory as the root CID in the plugin configuration | ||
|
||
# Develop | ||
|
||
- `make venv` | ||
- `make test` | ||
- `make build` | ||
|
||
# License information | ||
|
||
Source code license: [GPL v.3](http://www.gnu.org/copyleft/gpl.html) | ||
|
||
Fanart is from https://pixabay.com/nl/beaded-spinneweb-raagbol-web-dauw-1630493/ | ||
|
||
Icon is from https://pixabay.com/nl/puzzel-spel-kubus-rubiks-kubus-1243091/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<addon id="plugin.video.ipfs" | ||
version="0.0.2" | ||
name="IPFS" | ||
provider-name="ipfs.video"> | ||
<requires> | ||
<import addon="xbmc.python" version="2.25.0"/> | ||
<import addon="script.module.requests" version="2.19.1"/> | ||
</requires> | ||
<extension point="xbmc.python.pluginsource" library="main.py"> | ||
<provides>video</provides> | ||
</extension> | ||
<extension point="xbmc.addon.metadata"> | ||
<summary lang="en">IPFS video viewing plugin</summary> | ||
<description lang="en_GB">A plugin allowing access to IPFS video media.</description> | ||
<website>https://ipfs.video/</website> | ||
<assets> | ||
<icon>icon.png</icon> | ||
<fanart>fanart.jpg</fanart> | ||
<screenshot>resources\screenshot-01.jpg</screenshot> | ||
</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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
|
||
requests | ||
|
||
pytest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Kodi Media Center language file | ||
# Addon Name: IPFS | ||
# Addon id: plugin.video.ipfs | ||
# Addon Provider: ipfs.video | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: Kodi Addons\n" | ||
"Report-Msgid-Bugs-To: [email protected]\n" | ||
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||
"Last-Translator: Kodi Translation Team\n" | ||
"Language-Team: English (http://www.transifex.com/projects/p/xbmc-addons/language/en/)\n" | ||
"MIME-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
"Language: en\n" | ||
"Plural-Forms: nplurals=2; plural=(n != 1);\n" | ||
|
||
msgctxt "#32000" | ||
msgid "Root CID" | ||
msgstr "" | ||
|
||
msgctxt "#32001" | ||
msgid "IPFS Gateway" | ||
msgstr "" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="utf-8" standalone="yes"?> | ||
<settings> | ||
<category label="5"> | ||
<setting label="32000" type="text" id="rootCid" default="QmR4Ji6iTa8LeVXZLSgWwEao3jdnyj7yFTaANKQuqoVEBw" /> | ||
<setting label="32001" type="text" id="ipfsGateway" default="https://ipfs.io" /> | ||
</category> | ||
</settings> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from setuptools import setup | ||
|
||
setup(name='ipfs-video-kodi', | ||
version='0.1', | ||
description='The funniest joke in the world', | ||
url='', | ||
author='Flying Circus', | ||
author_email='[email protected]', | ||
license='MIT', | ||
packages=["src"], | ||
zip_safe=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
import requests | ||
import random | ||
|
||
def via(gateway): | ||
return IPFS(gateway) | ||
|
||
class IPFS: | ||
def __init__(self, gateway): | ||
assert len(gateway) > 0 | ||
self._gateway = gateway | ||
self._cache = {} | ||
|
||
def get(self, path, params): | ||
r = requests.get(self._gateway + '/api/v0/dag/get', params=params) | ||
r.raise_for_status() | ||
return r | ||
|
||
def list(self, hash): | ||
"""Get the directory content of the given hash""" | ||
assert type(hash) == str | ||
if hash in self._cache: | ||
if len(self._cache) > 50: | ||
#Drop 10 keys | ||
for k in random.sample(self._cache.keys(), 10): | ||
del self._cache[k] | ||
return self._cache[hash] | ||
|
||
r = self.get('/api/v0/dag/get', params={"arg": hash}) | ||
r.raise_for_status() | ||
|
||
entries = list(filter(lambda link: len(link['Name']) > 0 and '/' in link['Cid'], r.json()["links"])) | ||
self._cache[hash] = entries | ||
return entries | ||
|
||
def link(self, hash): | ||
return self._gateway + "/ipfs/" + hash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# -*- coding: utf-8 -*- | ||
import sys | ||
|
||
try: | ||
#Python 3 | ||
from urllib.parse import urlencode, parse_qsl | ||
except ImportError: | ||
from urllib import urlencode | ||
from urlparse import parse_qsl | ||
|
||
import xbmcgui | ||
import xbmcplugin | ||
import ipfs | ||
|
||
# Get the plugin url in plugin:// notation. | ||
_url = sys.argv[0] | ||
# Get the plugin handle as an integer number. | ||
_handle = int(sys.argv[1]) | ||
_rootCid = xbmcplugin.getSetting(_handle, 'rootCid') | ||
_ipfs = ipfs.via(xbmcplugin.getSetting(_handle, 'ipfsGateway')) | ||
|
||
def self_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 list_node(cid): | ||
""" | ||
Create a listing of the given ipfs cid | ||
:param cid: content identifier | ||
:type category: str | ||
""" | ||
# Set plugin category. It is displayed in some skins as the name | ||
# of the current section. | ||
xbmcplugin.setPluginCategory(_handle, cid) | ||
# Set plugin content. It allows Kodi to select appropriate views | ||
# for this type of content. | ||
xbmcplugin.setContent(_handle, 'videos') | ||
# Get the list of videos in the category. | ||
links = _ipfs.list(cid) | ||
|
||
for link in links: | ||
is_folder = len(_ipfs.list(link['Cid']['/'])) > 0 | ||
|
||
list_item = xbmcgui.ListItem(label=link['Name']) | ||
# Set additional info for the list item. | ||
# 'mediatype' is needed for skin to display info for this ListItem correctly. | ||
list_item.setInfo('video', {'title': link['Name'], | ||
'mediatype': 'video'}) | ||
# TODO set thumbnails | ||
# list_item.setArt({'thumb': video['thumb'], 'icon': video['thumb'], 'fanart': video['thumb']}) | ||
|
||
list_item.setProperty('IsPlayable', ('false' if is_folder else 'true')) | ||
|
||
url = self_url(action=('list' if is_folder else 'play'), cid=link['Cid']['/']) | ||
# 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_TITLE) | ||
xbmcplugin.endOfDirectory(_handle) | ||
|
||
|
||
def play_node(cid): | ||
""" | ||
Play a video by the provided cid. | ||
:param cid: Content id | ||
:type path: str | ||
""" | ||
play_item = xbmcgui.ListItem(path=_ipfs.link(cid)) | ||
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 | ||
""" | ||
params = dict(parse_qsl(paramstring)) | ||
|
||
#Default action | ||
if not params: | ||
params['action'] = 'list' | ||
params['cid'] = _rootCid | ||
|
||
# Check the parameters passed to the plugin | ||
if params['action'] == 'list': | ||
list_node(params['cid']) | ||
elif params['action'] == 'play': | ||
play_node(params['cid']) | ||
else: | ||
raise ValueError('Invalid paramstring: {0}!'.format(paramstring)) | ||
|
||
|
||
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:]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# -*- coding: utf-8 -*- | ||
import unittest | ||
import src.ipfs as ipfs | ||
|
||
test_gateway = ipfs.via("http://51.15.122.1") | ||
|
||
|
||
class TestIpfsMethods(unittest.TestCase): | ||
|
||
def test_list_file_should_be_empty(self): | ||
a = test_gateway.list("QmTNdv6MBhCjcGY5tpabi7aCeLZL65tmDzW37J9ZrFbZfL") | ||
self.assertEqual(a, []) | ||
|
||
def test_list_directory_should_work(self): | ||
a = test_gateway.list("QmVZV84e6nSwfA8LppiS4KXKiAhpbqqGYzofHtecQjd9js") | ||
self.assertEqual(len(a), 1) | ||
self.assertEqual(a[0]['Name'], "pexel") | ||
|
||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |