From d796f8fa86de51c8a7efab50c0fd70389f916567 Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 20:09:57 +0100 Subject: [PATCH 1/9] Add exception notification --- ipfs_video_kodi/main.py | 46 ++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/ipfs_video_kodi/main.py b/ipfs_video_kodi/main.py index 87ae7c0..1d841c8 100644 --- a/ipfs_video_kodi/main.py +++ b/ipfs_video_kodi/main.py @@ -47,27 +47,31 @@ def list_node(cid): # 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["hash"]["/"])) > 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["hash"]["/"]) - # 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) - + try: + links = _ipfs.list(cid) + for link in links: + is_folder = len(_ipfs.list(link["hash"]["/"])) > 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["hash"]["/"]) + # 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) + except Exception as e: + dialog = xbmcgui.Dialog() + dialog.ok("Failed to fetch information", str(e)) + raise + def play_node(cid): """ From e625dd1536e3d955e596af9a8c0998b70fa5aa3f Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:24:23 +0100 Subject: [PATCH 2/9] Add gateway settings item --- ipfs_video_kodi/ipfs/__init__.py | 7 +++++-- ipfs_video_kodi/main.py | 8 +++++--- resources/settings.xml | 4 ++-- test/test_ipfs.py | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/ipfs_video_kodi/ipfs/__init__.py b/ipfs_video_kodi/ipfs/__init__.py index 0ba6257..772e523 100644 --- a/ipfs_video_kodi/ipfs/__init__.py +++ b/ipfs_video_kodi/ipfs/__init__.py @@ -6,9 +6,11 @@ def via(gateway): return IPFS(gateway) + def lower_keys(dictList): return [{k.lower(): v for k, v in entry.items()} for entry in dictList] + class IPFS: def __init__(self, gateway): assert len(gateway) > 0 @@ -22,8 +24,9 @@ def get_links(self, path, params): rjson = r.json() return lower_keys( filter( - lambda link: len(link["Name"]) > 0 and "/" in link["Hash"], - rjson["Links"], + lambda link: len(link["Name"]) > 0 + and "/" in (link.get("Cid") or link["Hash"]), + rjson.get("links") or rjson["Links"], ) ) diff --git a/ipfs_video_kodi/main.py b/ipfs_video_kodi/main.py index 1d841c8..cc117b8 100644 --- a/ipfs_video_kodi/main.py +++ b/ipfs_video_kodi/main.py @@ -61,17 +61,19 @@ def list_node(cid): list_item.setProperty("IsPlayable", ("false" if is_folder else "true")) - url = self_url(action=("list" if is_folder else "play"), cid=link["hash"]["/"]) + url = self_url( + action=("list" if is_folder else "play"), cid=link["hash"]["/"] + ) # 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) except Exception as e: - dialog = xbmcgui.Dialog() + dialog = xbmcgui.Dialog() dialog.ok("Failed to fetch information", str(e)) raise - + def play_node(cid): """ diff --git a/resources/settings.xml b/resources/settings.xml index 9565bec..5f44892 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -2,6 +2,6 @@ - + - + \ No newline at end of file diff --git a/test/test_ipfs.py b/test/test_ipfs.py index 49797c7..6bb6a59 100644 --- a/test/test_ipfs.py +++ b/test/test_ipfs.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import unittest + import ipfs_video_kodi.ipfs as ipfs test_gateway = ipfs.via("https://ipfs.io") @@ -14,3 +15,16 @@ def test_list_directory_should_work(): ) b = test_gateway.list("QmYHDhsgUgdKSAimguGC92MzQ8VNFHZw3yp6kAHwiXCFLm") assert len(b) == 3 + + +@pytest.mark.skip(reason="uses remote systems") +def test_remote_apis(): + for gateway_url in [ + "http://127.0.0.1:8080", + "https://ipfs.io", + "https://dweb.link", + "https://gateway.pinata.cloud", + ]: + remote_gw = ipfs.via(gateway_url) + b = remote_gw.list("QmYHDhsgUgdKSAimguGC92MzQ8VNFHZw3yp6kAHwiXCFLm") + assert len(b) == 3, f"Should be able to get listing from {gateway_url}" From 82828df1827e8aaeaf88041f0a6a1681ab8e47ed Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:31:33 +0100 Subject: [PATCH 3/9] Fix import --- poetry.lock | 41 ++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + test/test_ipfs.py | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1c8d876..85506fb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -97,6 +97,23 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mypy" +version = "0.930" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = ">=1.1.0" +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] + [[package]] name = "mypy-extensions" version = "0.4.3" @@ -246,7 +263,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "5efc61e5e11dbf61fcf9c5621f676c29778d9251713d95a85c05ade4f852e261" +content-hash = "5f6fefd2127610f3a2e7c32a853ff7170ea0c38e31d3fea64572a4284f624afd" [metadata.files] atomicwrites = [ @@ -285,6 +302,28 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +mypy = [ + {file = "mypy-0.930-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871"}, + {file = "mypy-0.930-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31"}, + {file = "mypy-0.930-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b"}, + {file = "mypy-0.930-cp310-cp310-win_amd64.whl", hash = "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30"}, + {file = "mypy-0.930-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c"}, + {file = "mypy-0.930-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c"}, + {file = "mypy-0.930-cp36-cp36m-win_amd64.whl", hash = "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f"}, + {file = "mypy-0.930-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2"}, + {file = "mypy-0.930-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29"}, + {file = "mypy-0.930-cp37-cp37m-win_amd64.whl", hash = "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651"}, + {file = "mypy-0.930-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7"}, + {file = "mypy-0.930-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7"}, + {file = "mypy-0.930-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380"}, + {file = "mypy-0.930-cp38-cp38-win_amd64.whl", hash = "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01"}, + {file = "mypy-0.930-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae"}, + {file = "mypy-0.930-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f"}, + {file = "mypy-0.930-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95"}, + {file = "mypy-0.930-cp39-cp39-win_amd64.whl", hash = "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"}, + {file = "mypy-0.930-py3-none-any.whl", hash = "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173"}, + {file = "mypy-0.930.tar.gz", hash = "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2"}, +] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, diff --git a/pyproject.toml b/pyproject.toml index 1262938..12e89fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ requests = "^2.26.0" [tool.poetry.dev-dependencies] pytest = "^6.2.5" black = {version = "^21.12b0", allow-prereleases = true} +mypy = "^0.930" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/test/test_ipfs.py b/test/test_ipfs.py index 6bb6a59..4454773 100644 --- a/test/test_ipfs.py +++ b/test/test_ipfs.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -import unittest +import pytest import ipfs_video_kodi.ipfs as ipfs From 7c0c3b63a128c2a9eb114fe3d1a3c65164b23e59 Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:33:04 +0100 Subject: [PATCH 4/9] Fix CI check --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9d76b83..dd5409e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: - run: poetry install - name: static code analysis run: | - poetry run black --check + poetry run black --check ipfs_video_kodi test - run: poetry run pytest - name: build package run: | From 2a1715f100f2431f29b66ee03c084dc8ffe3188d Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:39:17 +0100 Subject: [PATCH 5/9] Add support for old api --- ipfs_video_kodi/ipfs/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ipfs_video_kodi/ipfs/__init__.py b/ipfs_video_kodi/ipfs/__init__.py index 772e523..c59a1a2 100644 --- a/ipfs_video_kodi/ipfs/__init__.py +++ b/ipfs_video_kodi/ipfs/__init__.py @@ -22,7 +22,7 @@ def get_links(self, path, params): r = requests.get(url, params=params, timeout=20) r.raise_for_status() rjson = r.json() - return lower_keys( + link_list = lower_keys( filter( lambda link: len(link["Name"]) > 0 and "/" in (link.get("Cid") or link["Hash"]), @@ -30,6 +30,12 @@ def get_links(self, path, params): ) ) + #Backwards compatibility + for i in link_list: + if 'cid' in i: + i['hash'] = i['cid'] + return link_list + def list(self, hash): """Get the directory content of the given hash""" assert type(hash) == str From 4565bbd0d4ddd34ee7189d9b697102e6a241133c Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:47:36 +0100 Subject: [PATCH 6/9] Push verison from pyproject.toml into addon.xml --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 9dd64b9..2e8152a 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,8 @@ 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 resources/settings.xml + VERSION=$(poetry version --short) + sed -i 's/id="plugin.video.ipfs" version="[^"]*"/id="plugin.video.ipfs" version="'${VERSION}'"/' addon.xml poetry build mkdir -p $(OUTPUT_PATH)/ipfs tar -xzf dist/ipfs-video-kodi-*.tar.gz -C dist --wildcards '*/ipfs_video_kodi' From 94afa6eb2d54ad72ed6e4d604ae8aad0ebd2e8e1 Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:48:36 +0100 Subject: [PATCH 7/9] Up the version --- addon.xml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon.xml b/addon.xml index 90779e9..8bc3802 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/pyproject.toml b/pyproject.toml index 12e89fc..8c5f3a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ipfs-video-kodi" -version = "0.0.6" +version = "0.0.7" description = "Kodi plugin to view IPFS video files" authors = ["Bram Neijt "] license = "GPLv3" From 1a5da1af699df5cd26dde52a3dd39bc2eb25a535 Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:49:44 +0100 Subject: [PATCH 8/9] Clean dist on clean --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2e8152a..a8f4617 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ OUTPUT_PATH=build/plugin.video.ipfs clean: rm -rf build + rm -rf dist build/plugin_video_ipfs.zip: build rm -f build/plugin_video_ipfs.zip From 8ed0f4c72ebf32cb92ff5dc5b44c8fdfd0e13e30 Mon Sep 17 00:00:00 2001 From: Bram Neijt Date: Sat, 1 Jan 2022 21:51:04 +0100 Subject: [PATCH 9/9] Formatting --- ipfs_video_kodi/ipfs/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipfs_video_kodi/ipfs/__init__.py b/ipfs_video_kodi/ipfs/__init__.py index c59a1a2..17e7976 100644 --- a/ipfs_video_kodi/ipfs/__init__.py +++ b/ipfs_video_kodi/ipfs/__init__.py @@ -30,10 +30,10 @@ def get_links(self, path, params): ) ) - #Backwards compatibility + # Backwards compatibility for i in link_list: - if 'cid' in i: - i['hash'] = i['cid'] + if "cid" in i: + i["hash"] = i["cid"] return link_list def list(self, hash):