179 lines
6.8 KiB
Python
179 lines
6.8 KiB
Python
# Copyright (C) 2023, Roman V. M.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
"""
|
|
Example video plugin that is compatible with Kodi 20.x "Nexus" and above
|
|
"""
|
|
import os
|
|
import sys
|
|
from urllib.parse import urlencode, parse_qsl
|
|
|
|
from lib.piped_api import PipedClient
|
|
|
|
from datetime import datetime
|
|
|
|
import xbmcgui
|
|
import xbmcplugin
|
|
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')
|
|
|
|
# Public domain movies are from https://publicdomainmovie.net
|
|
# Here we use a hardcoded list of movies simply for demonstrating purposes
|
|
# In a "real life" plugin you will need to get info and links to video files/streams
|
|
# from some website or online service.
|
|
|
|
PIPED = PipedClient(base_api_url=xbmcplugin.getSetting(int(sys.argv[1]), "base_api_url"))
|
|
|
|
def get_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 get_videos():
|
|
"""
|
|
Get the list of videofiles/streams.
|
|
|
|
Here you can insert some code that retrieves
|
|
the list of video streams in the given section from some site or API.
|
|
|
|
:return: the list of videos from the search results
|
|
:rtype: list
|
|
"""
|
|
query = xbmcgui.Dialog().input("Search Videos")
|
|
return PIPED.get_search_results(query, "videos")['items']
|
|
|
|
def list_videos():
|
|
"""
|
|
Create the list of playable videos in the Kodi interface.
|
|
"""
|
|
# Set plugin category. It is displayed in some skins as the name
|
|
# of the current section.
|
|
xbmcplugin.setPluginCategory(HANDLE, "Search Results")
|
|
# Set plugin content. It allows Kodi to select appropriate views
|
|
# for this type of content.
|
|
xbmcplugin.setContent(HANDLE, 'movies')
|
|
# Get the list of videos in the category.
|
|
videos = get_videos()
|
|
# Iterate through videos.
|
|
for video in videos:
|
|
# Create a list item with a text label
|
|
list_item = xbmcgui.ListItem(label=video['title'])
|
|
# Set graphics (thumbnail, fanart, banner, poster, landscape etc.) for the list item.
|
|
# Here we use only poster for simplicity's sake.
|
|
# In a real-life plugin you may need to set multiple image types.
|
|
list_item.setArt({'poster': video['thumbnail']})
|
|
# Set additional info for the list item via InfoTag.
|
|
# 'mediatype' is needed for skin to display info for this ListItem correctly.
|
|
info_tag = list_item.getVideoInfoTag()
|
|
info_tag.setMediaType('movie')
|
|
info_tag.setTitle(video['title'])
|
|
info_tag.setPlot(video['shortDescription'])
|
|
# info_tag.setYear(video['uploadedDate'])
|
|
# Set 'IsPlayable' property to 'true'.
|
|
# This is mandatory for playable items!
|
|
list_item.setProperty('IsPlayable', 'true')
|
|
# Create a URL for a plugin recursive call.
|
|
# Example: plugin://plugin.video.example/?action=play&video=https%3A%2F%2Fia600702.us.archive.org%2F3%2Fitems%2Firon_mask%2Firon_mask_512kb.mp4
|
|
# /watch?v= is 9 characters long, strip it
|
|
vidid = video['url'][9:]
|
|
url = get_url(action='play', video=vidid)
|
|
# Add the list item to a virtual Kodi folder.
|
|
# is_folder = False means that this item won't open any sub-list.
|
|
is_folder = False
|
|
# Add our item to the Kodi virtual folder listing.
|
|
xbmcplugin.addDirectoryItem(HANDLE, url, list_item, is_folder)
|
|
# Add sort methods for the virtual folder items
|
|
xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE)
|
|
xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_VIDEO_YEAR)
|
|
# Finish creating a virtual folder.
|
|
xbmcplugin.endOfDirectory(HANDLE)
|
|
|
|
|
|
def play_video(path):
|
|
"""
|
|
Play a video by the provided path.
|
|
|
|
:param path: Fully-qualified video URL
|
|
:type path: str
|
|
"""
|
|
# Create a playable item with a path to play.
|
|
# offscreen=True means that the list item is not meant for displaying,
|
|
# only to pass info to the Kodi player
|
|
play_item = xbmcgui.ListItem(offscreen=True)
|
|
play_item.setPath(path)
|
|
# Pass the item to the Kodi player.
|
|
xbmcplugin.setResolvedUrl(HANDLE, True, listitem=play_item)
|
|
|
|
def play_yt_video(vidid):
|
|
"""
|
|
Play a HLS video stream by the provided video ID.
|
|
|
|
:param path: Fully-qualified video URL
|
|
:type path: str
|
|
"""
|
|
# Create a playable item with a path to play.
|
|
# offscreen=True means that the list item is not meant for displaying,
|
|
# only to pass info to the Kodi player
|
|
play_item = xbmcgui.ListItem(offscreen=True)
|
|
play_item.setPath(PIPED.get_video(vidid).hls)
|
|
play_item.setProperty('inputstream', 'inputstream.adaptive')
|
|
play_item.setProperty('inputstream.adaptive.manifest_type', 'hls')
|
|
# Pass the item to the Kodi player.
|
|
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
|
|
"""
|
|
# Parse a URL-encoded paramstring to the dictionary of
|
|
# {<parameter>: <value>} elements
|
|
params = dict(parse_qsl(paramstring))
|
|
# Check the parameters passed to the plugin
|
|
if not params:
|
|
# If the plugin is called from Kodi UI without any parameters,
|
|
# display the list of video categories
|
|
list_videos()
|
|
elif params['action'] == 'play':
|
|
# Play a video from a provided URL.
|
|
play_yt_video(params['video'])
|
|
else:
|
|
# If the provided paramstring does not contain a supported action
|
|
# we raise an exception. This helps to catch coding errors,
|
|
# e.g. typos in action names.
|
|
raise ValueError(f'Invalid paramstring: {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:])
|