1
0
mirror of https://framagit.org/StCyr/plugin.video.peertube synced 2025-06-05 22:09:16 +02:00

Replace single quotes with double quotes

Make this a coding rule so that apostrophes don't need to be escaped in
strings (they are common in English and other languages).
This commit is contained in:
Thomas
2021-04-19 13:20:47 +00:00
parent 074be7aa12
commit 6f94e05398
5 changed files with 138 additions and 140 deletions

View File

@@ -77,13 +77,15 @@ The functions must be sorted alphabetically to make the maintenance easier.
## Coding style
The code is still based on the design of the alpha version so the coding style
is not mature yet.
A redesign is planned but until then please:
Here are the rules to follow when modifying the code:
* document the usage of functions following [Sphinx
format](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#python-signatures)
* use double quotes instead of single quotes when defining strings (to avoid
escaping apostrophes which are common characters in English and other
languages)
* follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) conventions. The
compliance can be checked with [pylint](https://www.pylint.org/) and the
compliance is checked in the `quality` job (more details are available in the
[CI file](.gitlab-ci.yml)). Pylint can also be run locally with the
following commands:
```python
@@ -91,11 +93,7 @@ python3 -m pip install -r misc/python_requirements.txt
python3 -m pylint --rcfile=misc/pylint-rcfile.txt
```
The pylint violations are also checked in the `quality` job.
More details are available in the [CI file](.gitlab-ci.yml).
Note: pylint is run with python3 to have latest features whereas the add-on
Note: pylint is run with python3 to have latest features even though the add-on
only supports Kodi v18 Leia (which uses python2)
## How to release a new version of this add-on

View File

@@ -36,7 +36,7 @@ class PeertubeAddon():
"""
# URL of the page which explains how to install libtorrent
HELP_URL = 'https://link.infini.fr/libtorrent-peertube-kodi'
HELP_URL = "https://link.infini.fr/libtorrent-peertube-kodi"
def __init__(self, plugin, plugin_id):
"""
@@ -49,19 +49,19 @@ class PeertubeAddon():
self.plugin_id = plugin_id
# Select preferred instance by default
self.selected_inst ='https://{}'\
.format(get_setting('preferred_instance'))
self.selected_inst ="https://{}"\
.format(get_setting("preferred_instance"))
# Get the number of videos to show per page
self.items_per_page = int(get_setting('items_per_page'))
self.items_per_page = int(get_setting("items_per_page"))
# Get the preferred resolution for video
self.preferred_resolution = get_setting('preferred_resolution')
self.preferred_resolution = get_setting("preferred_resolution")
# Nothing to play at initialisation
self.play = 0
self.torrent_name = ''
self.torrent_f = ''
self.torrent_name = ""
self.torrent_f = ""
# Check whether libtorrent could be imported by the service. The value
# of the associated property is retrieved only once and stored in an
@@ -69,14 +69,14 @@ class PeertubeAddon():
# of the service (we assume it is not possible to start the add-on
# before the service)
self.libtorrent_imported = \
get_property('libtorrent_imported') == 'True'
get_property("libtorrent_imported") == "True"
# Create a PeerTube object to send requests: settings which are used
# only by this object are directly retrieved from the settings
self.peertube = PeerTube(instance=self.selected_inst,
count=self.items_per_page,
sort=get_setting('video_sort_method'),
video_filter=get_setting('video_filter'))
sort=get_setting("video_sort_method"),
video_filter=get_setting("video_filter"))
def create_list(self, lst, data_type, start):
"""
@@ -86,68 +86,68 @@ class PeertubeAddon():
"""
# Create a list for our items.
listing = []
for data in lst['data']:
for data in lst["data"]:
# Create a list item with a text label
list_item = xbmcgui.ListItem(label=data['name'])
list_item = xbmcgui.ListItem(label=data["name"])
if data_type == 'videos':
if data_type == "videos":
# Add thumbnail
list_item.setArt({
'thumb': '{0}/{1}'.format(self.selected_inst,
data['thumbnailPath'])})
"thumb": "{0}/{1}".format(self.selected_inst,
data["thumbnailPath"])})
# Set a fanart image for the list item.
# list_item.setProperty('fanart_image', data['thumb'])
# list_item.setProperty("fanart_image", data["thumb"])
# Compute media info from item's metadata
info = {'title': data['name'],
'playcount': data['views'],
'plotoutline': data['description'],
'duration': data['duration']
info = {"title": data["name"],
"playcount": data["views"],
"plotoutline": data["description"],
"duration": data["duration"]
}
# For videos, add a rating based on likes and dislikes
if data['likes'] > 0 or data['dislikes'] > 0:
info['rating'] = data['likes'] / (
data['likes'] + data['dislikes'])
if data["likes"] > 0 or data["dislikes"] > 0:
info["rating"] = data["likes"] / (
data["likes"] + data["dislikes"])
# Set additional info for the list item.
list_item.setInfo('video', info)
list_item.setInfo("video", info)
# Videos are playable
list_item.setProperty('IsPlayable', 'true')
list_item.setProperty("IsPlayable", "true")
# Build the Kodi URL to play the associated video only with the
# id of the video. The instance is omitted because the
# currently selected instance will be used automatically.
url = self.build_kodi_url({
'action': 'play_video',
'id': data['uuid']
"action": "play_video",
"id": data["uuid"]
})
elif data_type == 'instances':
elif data_type == "instances":
# TODO: Add a context menu to select instance as preferred
# Instances are not playable
list_item.setProperty('IsPlayable', 'false')
list_item.setProperty("IsPlayable", "false")
# Set URL to select this instance
url = self.build_kodi_url({
'action': 'select_instance',
'url': data['host']
"action": "select_instance",
"url": data["host"]
})
# Add our item to the listing as a 3-element tuple.
listing.append((url, list_item, False))
# Add a 'Next page' button when there are more data to show
# Add a "Next page" button when there are more data to show
start = int(start) + self.items_per_page
if lst['total'] > start:
list_item = xbmcgui.ListItem(label='Next page ({0})'
if lst["total"] > start:
list_item = xbmcgui.ListItem(label="Next page ({0})"
.format(start/self.items_per_page))
url = self.build_kodi_url({
'action': 'browse_{0}'.format(data_type),
'start': start})
"action": "browse_{0}".format(data_type),
"start": start})
listing.append((url, list_item, True))
return listing
@@ -168,8 +168,8 @@ class PeertubeAddon():
else:
# If an instance was provided (external call), ensure the URL is
# prefixed with HTTPS
if not instance.startswith('https://'):
instance = 'https://{}'.format(instance)
if not instance.startswith("https://"):
instance = "https://{}".format(instance)
# Retrieve the information about the video
metadata = self.peertube.get_video(video_id)
@@ -178,46 +178,46 @@ class PeertubeAddon():
# different resolutions available for a video may be stored in "files"
# or "streamingPlaylists[].files". Note that "files" will always exist
# in the response but may be empty.
if len(metadata['files']) != 0:
files = metadata['files']
if len(metadata["files"]) != 0:
files = metadata["files"]
else:
files = metadata['streamingPlaylists'][0]['files']
files = metadata["streamingPlaylists"][0]["files"]
debug('Looking for the best resolution matching the user preferences')
debug("Looking for the best resolution matching the user preferences")
current_res = 0
higher_res = -1
torrent_url = ''
torrent_url = ""
for f in files:
# Get the resolution
res = f['resolution']['id']
res = f["resolution"]["id"]
if res == self.preferred_resolution:
# Stop directly when we find the exact same resolution as the
# user's preferred one
debug('Found video with preferred resolution')
torrent_url = f['torrentUrl']
debug("Found video with preferred resolution")
torrent_url = f["torrentUrl"]
break
elif res < self.preferred_resolution and res > current_res:
# Otherwise, try to find the best one just below the user's
# preferred one
debug('Found video with good lower resolution ({0})'
.format(f['resolution']['label']))
torrent_url = f['torrentUrl']
debug("Found video with good lower resolution ({0})"
.format(f["resolution"]["label"]))
torrent_url = f["torrentUrl"]
current_res = res
elif (res > self.preferred_resolution
and (res < higher_res or higher_res == -1)):
# In the worst case, we'll take the one just above the user's
# preferred one
debug('Saving video with higher resolution ({0}) as a possible'
' alternative'.format(f['resolution']['label']))
backup_url = f['torrentUrl']
debug("Saving video with higher resolution ({0}) as a possible"
" alternative".format(f["resolution"]["label"]))
backup_url = f["torrentUrl"]
higher_res = res
# When we didn't find a resolution equal or lower than the user's
# preferred one, use the resolution just above the preferred one
if not torrent_url:
debug('Using video with higher resolution as alternative')
debug("Using video with higher resolution as alternative")
torrent_url = backup_url
return torrent_url
@@ -232,7 +232,7 @@ class PeertubeAddon():
# Ask the user which keywords must be searched for
keywords = xbmcgui.Dialog().input(
heading='Search videos on {}'.format(self.selected_inst),
heading="Search videos on {}".format(self.selected_inst),
type=xbmcgui.INPUT_ALPHANUM)
# Go back to main menu when user cancels
@@ -244,12 +244,12 @@ class PeertubeAddon():
# Exit directly when no result is found
if not results:
notif_warning(title='No videos found',
message='No videos found matching the query.')
notif_warning(title="No videos found",
message="No videos found matching the query.")
return
# Create array of xmbcgui.ListItem's
listing = self.create_list(results, 'videos', start)
listing = self.create_list(results, "videos", start)
# Add our listing to Kodi.
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
@@ -267,7 +267,7 @@ class PeertubeAddon():
results = self.peertube.list_videos(start)
# Create array of xmbcgui.ListItem's
listing = self.create_list(results, 'videos', start)
listing = self.create_list(results, "videos", start)
# Add our listing to Kodi.
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
@@ -283,7 +283,7 @@ class PeertubeAddon():
results = list_instances(start)
# Create array of xmbcgui.ListItem's
listing = self.create_list(results, 'instances', start)
listing = self.create_list(results, "instances", start)
# Add our listing to Kodi.
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
@@ -297,9 +297,9 @@ class PeertubeAddon():
:param data: dict
"""
debug('Received metadata_downloaded signal, will start playing media')
debug("Received metadata_downloaded signal, will start playing media")
self.play = 1
self.torrent_f = data['file']
self.torrent_f = data["file"]
def play_video(self, torrent_url):
"""
@@ -309,21 +309,21 @@ class PeertubeAddon():
# If libtorrent could not be imported, display a message and do not try
# download nor play the video as it will fail.
if not self.libtorrent_imported:
open_dialog(title='Error: libtorrent could not be imported',
message='PeerTube cannot play videos without'
' libtorrent.\nPlease follow the instructions'
' at {}'.format(self.HELP_URL))
open_dialog(title="Error: libtorrent could not be imported",
message="PeerTube cannot play videos without"
" libtorrent.\nPlease follow the instructions"
" at {}".format(self.HELP_URL))
return
debug('Starting torrent download ({0})'.format(torrent_url))
debug("Starting torrent download ({0})".format(torrent_url))
# Start a downloader thread
AddonSignals.sendSignal('start_download', {'url': torrent_url})
AddonSignals.sendSignal("start_download", {"url": torrent_url})
# Wait until the PeerTubeDownloader has downloaded all the torrent's
# metadata
AddonSignals.registerSlot('plugin.video.peertube',
'metadata_downloaded',
AddonSignals.registerSlot("plugin.video.peertube",
"metadata_downloaded",
self.play_video_continue)
timeout = 0
while self.play == 0 and timeout < 10:
@@ -332,35 +332,35 @@ class PeertubeAddon():
# Abort in case of timeout
if timeout == 10:
notif_error(title='Download timeout',
message='Timeout fetching {}'.format(torrent_url))
notif_error(title="Download timeout",
message="Timeout fetching {}".format(torrent_url))
return
else:
# Wait a little before starting playing the torrent
xbmc.sleep(3000)
# Pass the item to the Kodi player for actual playback.
debug('Starting video playback ({0})'.format(torrent_url))
debug("Starting video playback ({0})".format(torrent_url))
play_item = xbmcgui.ListItem(path=self.torrent_f)
xbmcplugin.setResolvedUrl(self.plugin_id, True, listitem=play_item)
def select_instance(self, instance):
"""
Change currently selected instance to 'instance' parameter
Change currently selected instance to "instance" parameter
:param instance: str
"""
# Update the object attribute even though it is not used currently but
# it may be useful in case reuselanguageinvoker is enabled.
self.selected_inst = 'https://{}'.format(instance)
self.selected_inst = "https://{}".format(instance)
# Update the preferred instance in the settings so that this choice is
# reused on the next run and the next call of the add-on
set_setting('preferred_instance', instance)
set_setting("preferred_instance", instance)
# Notify the user and log the event
message = '{0} is now the selected instance'.format(self.selected_inst)
notif_info(title='Current instance changed',
message = "{0} is now the selected instance".format(self.selected_inst)
notif_info(title="Current instance changed",
message=message)
debug(message)
@@ -371,7 +371,7 @@ class PeertubeAddon():
encoded in the URL
"""
return '{0}?{1}'.format(self.plugin_url, urlencode(parameters))
return "{0}?{1}".format(self.plugin_url, urlencode(parameters))
def main_menu(self):
"""
@@ -382,18 +382,18 @@ class PeertubeAddon():
listing = []
# 1st menu entry
list_item = xbmcgui.ListItem(label='Browse selected instance')
url = self.build_kodi_url({'action': 'browse_videos', 'start': 0})
list_item = xbmcgui.ListItem(label="Browse selected instance")
url = self.build_kodi_url({"action": "browse_videos", "start": 0})
listing.append((url, list_item, True))
# 2nd menu entry
list_item = xbmcgui.ListItem(label='Search on selected instance')
url = self.build_kodi_url({'action': 'search_videos', 'start': 0})
list_item = xbmcgui.ListItem(label="Search on selected instance")
url = self.build_kodi_url({"action": "search_videos", "start": 0})
listing.append((url, list_item, True))
# 3rd menu entry
list_item = xbmcgui.ListItem(label='Select other instance')
url = self.build_kodi_url({'action': 'browse_instances', 'start': 0})
list_item = xbmcgui.ListItem(label="Select other instance")
url = self.build_kodi_url({"action": "browse_instances", "start": 0})
listing.append((url, list_item, True))
# Add our listing to Kodi.
@@ -415,27 +415,27 @@ class PeertubeAddon():
# Check the parameters passed to the plugin
if params:
action = params['action']
if action == 'browse_videos':
action = params["action"]
if action == "browse_videos":
# Browse videos on selected instance
self.browse_videos(params['start'])
elif action == 'search_videos':
self.browse_videos(params["start"])
elif action == "search_videos":
# Search for videos on selected instance
self.search_videos(params['start'])
elif action == 'browse_instances':
self.search_videos(params["start"])
elif action == "browse_instances":
# Browse peerTube instances
self.browse_instances(params['start'])
elif action == 'play_video':
self.browse_instances(params["start"])
elif action == "play_video":
# This action comes with the id of the video to play as
# parameter. The instance may also be in the parameters. Use
# these parameters to retrieve the complete URL (containing the
# resolution).
url = self.get_video_url(instance=params.get('instance'),
video_id=params.get('id'))
url = self.get_video_url(instance=params.get("instance"),
video_id=params.get("id"))
# Play the video using the URL
self.play_video(url)
elif action == 'select_instance':
self.select_instance(params['url'])
elif action == "select_instance":
self.select_instance(params["url"])
else:
# Display the addon's main menu when the plugin is called from
# Kodi UI without any parameters
@@ -443,13 +443,13 @@ class PeertubeAddon():
# Display a warning if libtorrent could not be imported
if not self.libtorrent_imported:
open_dialog(title='Error: libtorrent could not be imported',
message='You can still browse and search videos'
' but you will not be able to play them.\n'
'Please follow the instructions at {}'
open_dialog(title="Error: libtorrent could not be imported",
message="You can still browse and search videos"
" but you will not be able to play them.\n"
"Please follow the instructions at {}"
.format(self.HELP_URL))
if __name__ == '__main__':
if __name__ == "__main__":
# Initialise addon
addon = PeertubeAddon(sys.argv[0], int(sys.argv[1]))

View File

@@ -19,7 +19,7 @@ def debug(message):
(the name is hard-coded to avoid calling xbmcaddon each time since the name
should not change)
"""
xbmc.log('[PeerTube] {}'.format(message), xbmc.LOGDEBUG)
xbmc.log("[PeerTube] {}".format(message), xbmc.LOGDEBUG)
def get_property(name):
"""Retrieve the value of a window property related to the add-on
@@ -29,7 +29,7 @@ def get_property(name):
:return: Value of the window property
:rtype: str
"""
return xbmcgui.Window(10000).getProperty('peertube_{}'.format(name))
return xbmcgui.Window(10000).getProperty("peertube_{}".format(name))
def get_setting(setting_name):
"""Retrieve the value of a setting
@@ -85,7 +85,7 @@ def set_property(name, value):
actual name of the property is prefixed with "peertube_")
:param str value: New value of the property
"""
xbmcgui.Window(10000).setProperty('peertube_{}'.format(name), value)
xbmcgui.Window(10000).setProperty("peertube_{}".format(name), value)
def set_setting(setting_name, setting_value):
"""Modify the value of a setting

View File

@@ -34,10 +34,10 @@ class PeerTube:
# The value "video_filter" is directly retrieved from the settings so
# it must be converted into one of the expected values by the REST APIs
if 'all-local' in video_filter:
self.filter = 'all-local'
if "all-local" in video_filter:
self.filter = "all-local"
else:
self.filter = 'local'
self.filter = "local"
def _request(self, method, url, params=None, data=None):
"""Call a REST API on the instance

View File

@@ -39,7 +39,7 @@ class PeertubeDownloader(Thread):
:param str message: Message to log (will be prefixed with the name of
the class)
"""
debug('PeertubeDownloader: {}'.format(message))
debug("PeertubeDownloader: {}".format(message))
def run(self):
"""
@@ -48,20 +48,20 @@ class PeertubeDownloader(Thread):
:return: None
"""
self.debug('Opening BitTorent session')
self.debug("Opening BitTorent session")
# Open BitTorrent session
ses = libtorrent.session()
ses.listen_on(6881, 6891)
# Add torrent
self.debug('Adding torrent {}'.format(self.torrent))
h = ses.add_torrent({'url': self.torrent, 'save_path': self.temp_dir})
self.debug("Adding torrent {}".format(self.torrent))
h = ses.add_torrent({"url": self.torrent, "save_path": self.temp_dir})
# Set sequential mode to allow watching while downloading
h.set_sequential_download(True)
# Download torrent
self.debug('Downloading torrent {}'.format(self.torrent))
self.debug("Downloading torrent {}".format(self.torrent))
signal_sent = 0
while not h.is_seed():
xbmc.sleep(1000)
@@ -69,11 +69,11 @@ class PeertubeDownloader(Thread):
# Inform addon that all the metadata has been downloaded and that
# it may start playing the torrent
if s.state >=3 and signal_sent == 0:
self.debug('Received all torrent metadata, notifying'
' PeertubeAddon')
self.debug("Received all torrent metadata, notifying"
" PeertubeAddon")
i = h.torrent_file()
f = self.temp_dir + i.name()
AddonSignals.sendSignal('metadata_downloaded', {'file': f})
AddonSignals.sendSignal("metadata_downloaded", {"file": f})
signal_sent = 1
class PeertubeService():
@@ -86,8 +86,8 @@ class PeertubeService():
PeertubeService initialisation function
"""
# Create our temporary directory
self.temp = '{}{}'.format(xbmc.translatePath('special://temp'),
'plugin.video.peertube/')
self.temp = "{}{}".format(xbmc.translatePath("special://temp"),
"plugin.video.peertube/")
if not xbmcvfs.exists(self.temp):
xbmcvfs.mkdir(self.temp)
@@ -97,17 +97,17 @@ class PeertubeService():
:param str message: Message to log (will be prefixed with the name of
the class)
"""
debug('PeertubeService: {}'.format(message))
debug("PeertubeService: {}".format(message))
def download_torrent(self, data):
"""
Start a downloader thread to download torrent specified by data['url']
Start a downloader thread to download torrent specified by data["url"]
:param data: dict
:return: None
"""
self.debug('Received a start_download signal')
downloader = PeertubeDownloader(data['url'], self.temp)
self.debug("Received a start_download signal")
downloader = PeertubeDownloader(data["url"], self.temp)
downloader.start()
def run(self):
@@ -118,25 +118,25 @@ class PeertubeService():
thread when needed, and exit when Kodi is shutting down.
"""
self.debug('Starting')
self.debug("Starting")
# Launch the download_torrent callback function when the
# 'start_download' signal is received
AddonSignals.registerSlot('plugin.video.peertube',
'start_download',
# "start_download" signal is received
AddonSignals.registerSlot("plugin.video.peertube",
"start_download",
self.download_torrent)
# Monitor Kodi's shutdown signal
self.debug('Service started, waiting for signals')
self.debug("Service started, waiting for signals")
monitor = xbmc.Monitor()
while not monitor.abortRequested():
if monitor.waitForAbort(1):
# Abort was requested while waiting. We must exit
# TODO: Clean temporary directory
self.debug('Exiting')
self.debug("Exiting")
break
if __name__ == '__main__':
if __name__ == "__main__":
# Create a PeertubeService instance
service = PeertubeService()
@@ -146,12 +146,12 @@ if __name__ == '__main__':
LIBTORRENT_IMPORTED = True
except ImportError as exception:
LIBTORRENT_IMPORTED = False
service.debug('The libtorrent library could not be imported because of'
' the following error:\n{}'.format(exception))
service.debug("The libtorrent library could not be imported because of"
" the following error:\n{}".format(exception))
# Save whether libtorrent could be imported as a window property so that
# this information can be retrieved by the add-on
set_property('libtorrent_imported', str(LIBTORRENT_IMPORTED))
set_property("libtorrent_imported", str(LIBTORRENT_IMPORTED))
# Start the service
service.run()