Guide the user when libtorrent cannot be imported
Libtorrent is required to play videos but its installation is still manual so now a message is displayed when libtorrent could not be imported instead of having a "service could not start" error at Kodi startup. The message contains a link to a page which explains how to install libtorrent. It will be displayed when: * the add-on starts * the user selects a video to play (including when called externally) Other additions: * Create a kodi_utils module to centralize some calls to the Kodi API * Add license information in the header of the files * Ignore some files in Git (python cache and Mac OS system file)
This commit is contained in:
parent
7a21bd92ac
commit
4346178db9
|
@ -0,0 +1,3 @@
|
||||||
|
.DS_Store
|
||||||
|
*.pyo
|
||||||
|
*.pyc
|
111
peertube.py
111
peertube.py
|
@ -1,13 +1,13 @@
|
||||||
""" A Kodi Addon to play video hosted on the PeerTube service
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
A Kodi add-on to play video hosted on the PeerTube service
|
||||||
(http://joinpeertube.org/)
|
(http://joinpeertube.org/)
|
||||||
|
|
||||||
TODO:
|
Copyright (C) 2018 Cyrille Bollu
|
||||||
- Delete downloaded files by default
|
Copyright (C) 2021 Thomas Bétous
|
||||||
- Allow people to choose if they want to keep their download after watching?
|
|
||||||
- Do sanity checks on received data
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
- Handle languages better (with .po files)
|
See LICENSE.txt for more information.
|
||||||
- Get the best quality torrent given settings and/or available bandwidth
|
|
||||||
See how they do that in the peerTube client's code
|
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -26,17 +26,22 @@ import xbmcaddon
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import xbmcplugin
|
import xbmcplugin
|
||||||
|
|
||||||
|
from resources.lib.kodi_utils import debug, get_property, notif_error, \
|
||||||
|
notif_info, notif_warning, open_dialog
|
||||||
|
|
||||||
|
|
||||||
class PeertubeAddon():
|
class PeertubeAddon():
|
||||||
"""
|
"""
|
||||||
Main class of the addon
|
Main class of the addon
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# URL of the page which explains how to install libtorrent
|
||||||
|
HELP_URL = 'https://link.infini.fr/peertube-kodi-libtorrent'
|
||||||
|
|
||||||
def __init__(self, plugin, plugin_id):
|
def __init__(self, plugin, plugin_id):
|
||||||
"""
|
"""
|
||||||
Initialisation of the PeertubeAddon class
|
Initialisation of the PeertubeAddon class
|
||||||
:param plugin, plugin_id: str, int
|
:param plugin, plugin_id: str, int
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# These 2 steps must be done first since the logging function requires
|
# These 2 steps must be done first since the logging function requires
|
||||||
|
@ -46,8 +51,6 @@ class PeertubeAddon():
|
||||||
# Get the add-on name
|
# Get the add-on name
|
||||||
self.addon_name = addon.getAddonInfo('name')
|
self.addon_name = addon.getAddonInfo('name')
|
||||||
|
|
||||||
self.debug('Initialising')
|
|
||||||
|
|
||||||
# Save addon URL and ID
|
# Save addon URL and ID
|
||||||
self.plugin_url = plugin
|
self.plugin_url = plugin
|
||||||
self.plugin_id = plugin_id
|
self.plugin_id = plugin_id
|
||||||
|
@ -77,15 +80,21 @@ class PeertubeAddon():
|
||||||
else:
|
else:
|
||||||
self.video_filter = 'local'
|
self.video_filter = 'local'
|
||||||
|
|
||||||
return None
|
# Check whether libtorrent could be imported by the service. The value
|
||||||
|
# of the associated property is retrieved only once and stored in an
|
||||||
|
# attribute because libtorrent is imported only once at the beginning
|
||||||
|
# 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'
|
||||||
|
|
||||||
def debug(self, message):
|
def debug(self, message):
|
||||||
"""Log a message in Kodi's log with the level xbmc.LOGDEBUG
|
"""Log a debug message
|
||||||
|
|
||||||
:param message: Message to log
|
:param str message: Message to log (will be prefixed with the add-on
|
||||||
:type message: str
|
name)
|
||||||
"""
|
"""
|
||||||
xbmc.log('{0}: {1}'.format(self.addon_name, message), xbmc.LOGDEBUG)
|
debug('{0}: {1}'.format(self.addon_name, message))
|
||||||
|
|
||||||
def query_peertube(self, req):
|
def query_peertube(self, req):
|
||||||
"""
|
"""
|
||||||
|
@ -104,10 +113,8 @@ class PeertubeAddon():
|
||||||
try:
|
try:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except requests.HTTPError as e:
|
except requests.HTTPError as e:
|
||||||
xbmcgui.Dialog().notification('Communication error',
|
notif_error(title='Communication error',
|
||||||
'Error when sending request {0}'
|
message='Error when sending request {}'.format(req))
|
||||||
.format(req),
|
|
||||||
xbmcgui.NOTIFICATION_ERROR)
|
|
||||||
# If the JSON contains an 'error' key, print it
|
# If the JSON contains an 'error' key, print it
|
||||||
error_details = data.get('error')
|
error_details = data.get('error')
|
||||||
if error_details is not None:
|
if error_details is not None:
|
||||||
|
@ -336,7 +343,6 @@ class PeertubeAddon():
|
||||||
in the results
|
in the results
|
||||||
|
|
||||||
:param start: string
|
:param start: string
|
||||||
:result: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Show a 'Search videos' dialog
|
# Show a 'Search videos' dialog
|
||||||
|
@ -346,7 +352,7 @@ class PeertubeAddon():
|
||||||
|
|
||||||
# Go back to main menu when user cancels
|
# Go back to main menu when user cancels
|
||||||
if not search:
|
if not search:
|
||||||
return None
|
return
|
||||||
|
|
||||||
# Create the PeerTube REST API request for searching videos
|
# Create the PeerTube REST API request for searching videos
|
||||||
req = self.build_video_rest_api_request(search, start)
|
req = self.build_video_rest_api_request(search, start)
|
||||||
|
@ -356,10 +362,9 @@ class PeertubeAddon():
|
||||||
|
|
||||||
# Exit directly when no result is found
|
# Exit directly when no result is found
|
||||||
if not results:
|
if not results:
|
||||||
xbmcgui.Dialog().notification('No videos found',
|
notif_warning(title='No videos found',
|
||||||
'No videos found matching query',
|
message='No videos found matching the query.')
|
||||||
xbmcgui.NOTIFICATION_WARNING)
|
return
|
||||||
return None
|
|
||||||
|
|
||||||
# Create array of xmbcgui.ListItem's
|
# Create array of xmbcgui.ListItem's
|
||||||
listing = self.create_list(results, 'videos', start)
|
listing = self.create_list(results, 'videos', start)
|
||||||
|
@ -368,15 +373,12 @@ class PeertubeAddon():
|
||||||
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
||||||
xbmcplugin.endOfDirectory(self.plugin_id)
|
xbmcplugin.endOfDirectory(self.plugin_id)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def browse_videos(self, start):
|
def browse_videos(self, start):
|
||||||
"""
|
"""
|
||||||
Function to navigate through all the video published by a PeerTube
|
Function to navigate through all the video published by a PeerTube
|
||||||
instance
|
instance
|
||||||
|
|
||||||
:param start: string
|
:param start: string
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Create the PeerTube REST API request for listing videos
|
# Create the PeerTube REST API request for listing videos
|
||||||
|
@ -392,13 +394,10 @@ class PeertubeAddon():
|
||||||
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
||||||
xbmcplugin.endOfDirectory(self.plugin_id)
|
xbmcplugin.endOfDirectory(self.plugin_id)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def browse_instances(self, start):
|
def browse_instances(self, start):
|
||||||
"""
|
"""
|
||||||
Function to navigate through all PeerTube instances
|
Function to navigate through all PeerTube instances
|
||||||
:param start: str
|
:param start: str
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Create the PeerTube REST API request for browsing PeerTube instances
|
# Create the PeerTube REST API request for browsing PeerTube instances
|
||||||
|
@ -414,15 +413,12 @@ class PeertubeAddon():
|
||||||
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
xbmcplugin.addDirectoryItems(self.plugin_id, listing, len(listing))
|
||||||
xbmcplugin.endOfDirectory(self.plugin_id)
|
xbmcplugin.endOfDirectory(self.plugin_id)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def play_video_continue(self, data):
|
def play_video_continue(self, data):
|
||||||
"""
|
"""
|
||||||
Callback function to let the play_video function resume when the
|
Callback function to let the play_video function resume when the
|
||||||
PeertubeDownloader has downloaded all the torrent's metadata
|
PeertubeDownloader has downloaded all the torrent's metadata
|
||||||
|
|
||||||
:param data: dict
|
:param data: dict
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.debug(
|
self.debug(
|
||||||
|
@ -430,14 +426,19 @@ class PeertubeAddon():
|
||||||
self.play = 1
|
self.play = 1
|
||||||
self.torrent_f = data['file']
|
self.torrent_f = data['file']
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def play_video(self, torrent_url):
|
def play_video(self, torrent_url):
|
||||||
"""
|
"""
|
||||||
Start the torrent's download and play it while being downloaded
|
Start the torrent's download and play it while being downloaded
|
||||||
:param torrent_url: str
|
:param torrent_url: str
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
# 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))
|
||||||
|
return
|
||||||
|
|
||||||
self.debug('Starting torrent download ({0})'.format(torrent_url))
|
self.debug('Starting torrent download ({0})'.format(torrent_url))
|
||||||
|
|
||||||
|
@ -456,11 +457,9 @@ class PeertubeAddon():
|
||||||
|
|
||||||
# Abort in case of timeout
|
# Abort in case of timeout
|
||||||
if timeout == 10:
|
if timeout == 10:
|
||||||
xbmcgui.Dialog().notification('Download timeout',
|
notif_error(title='Download timeout',
|
||||||
'Timeout fetching {}'
|
message='Timeout fetching {}'.format(torrent_url))
|
||||||
.format(torrent_url),
|
return
|
||||||
xbmcgui.NOTIFICATION_ERROR)
|
|
||||||
return None
|
|
||||||
else:
|
else:
|
||||||
# Wait a little before starting playing the torrent
|
# Wait a little before starting playing the torrent
|
||||||
xbmc.sleep(3000)
|
xbmc.sleep(3000)
|
||||||
|
@ -470,25 +469,19 @@ class PeertubeAddon():
|
||||||
play_item = xbmcgui.ListItem(path=self.torrent_f)
|
play_item = xbmcgui.ListItem(path=self.torrent_f)
|
||||||
xbmcplugin.setResolvedUrl(self.plugin_id, True, listitem=play_item)
|
xbmcplugin.setResolvedUrl(self.plugin_id, True, listitem=play_item)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def select_instance(self, instance):
|
def select_instance(self, instance):
|
||||||
"""
|
"""
|
||||||
Change currently selected instance to 'instance' parameter
|
Change currently selected instance to 'instance' parameter
|
||||||
:param instance: str
|
:param instance: str
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.selected_inst = 'https://{}'.format(instance)
|
self.selected_inst = 'https://{}'.format(instance)
|
||||||
xbmcgui.Dialog().notification('Current instance changed',
|
notif_info(title='Current instance changed',
|
||||||
'Changed current instance to {0}'
|
message='Changed current instance to {0}'
|
||||||
.format(self.selected_inst),
|
.format(self.selected_inst))
|
||||||
xbmcgui.NOTIFICATION_INFO)
|
|
||||||
self.debug('Changing currently selected instance to {0}'
|
self.debug('Changing currently selected instance to {0}'
|
||||||
.format(self.selected_inst))
|
.format(self.selected_inst))
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def build_kodi_url(self, parameters):
|
def build_kodi_url(self, parameters):
|
||||||
"""Build a Kodi URL based on the parameters.
|
"""Build a Kodi URL based on the parameters.
|
||||||
|
|
||||||
|
@ -501,8 +494,6 @@ class PeertubeAddon():
|
||||||
def main_menu(self):
|
def main_menu(self):
|
||||||
"""
|
"""
|
||||||
Addon's main menu
|
Addon's main menu
|
||||||
:param: None
|
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Create a list for our items.
|
# Create a list for our items.
|
||||||
|
@ -529,14 +520,11 @@ class PeertubeAddon():
|
||||||
# Finish creating a virtual folder.
|
# Finish creating a virtual folder.
|
||||||
xbmcplugin.endOfDirectory(self.plugin_id)
|
xbmcplugin.endOfDirectory(self.plugin_id)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def router(self, paramstring):
|
def router(self, paramstring):
|
||||||
"""
|
"""
|
||||||
Router function that calls other functions
|
Router function that calls other functions
|
||||||
depending on the provided paramstring
|
depending on the provided paramstring
|
||||||
:param paramstring: dict
|
:param paramstring: dict
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Parse a URL-encoded paramstring to the dictionary of
|
# Parse a URL-encoded paramstring to the dictionary of
|
||||||
|
@ -571,8 +559,13 @@ class PeertubeAddon():
|
||||||
# Kodi UI without any parameters
|
# Kodi UI without any parameters
|
||||||
self.main_menu()
|
self.main_menu()
|
||||||
|
|
||||||
return None
|
# 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 {}'
|
||||||
|
.format(self.HELP_URL))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Copyright (C) 2021 Thomas Bétous
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
See LICENSE.txt for more information.
|
||||||
|
"""
|
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Copyright (C) 2021 Thomas Bétous
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
See LICENSE.txt for more information.
|
||||||
|
"""
|
|
@ -0,0 +1,76 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Utility functions to interact easily with Kodi
|
||||||
|
|
||||||
|
Copyright (C) 2021 Thomas Bétous
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
See LICENSE.txt for more information.
|
||||||
|
"""
|
||||||
|
import xbmc
|
||||||
|
import xbmcgui
|
||||||
|
|
||||||
|
|
||||||
|
def debug(message):
|
||||||
|
"""Log a message in Kodi's log with the level xbmc.LOGDEBUG
|
||||||
|
|
||||||
|
:param str message: Message to log
|
||||||
|
"""
|
||||||
|
xbmc.log(message, xbmc.LOGDEBUG)
|
||||||
|
|
||||||
|
def get_property(name):
|
||||||
|
"""Retrieve the value of a window property related to the add-on
|
||||||
|
|
||||||
|
:param str name: name of the property which value will be retrieved (the
|
||||||
|
actual name of the property is prefixed with "peertube_")
|
||||||
|
:return: the value of the window property
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return xbmcgui.Window(10000).getProperty('peertube_{}'.format(name))
|
||||||
|
|
||||||
|
def notif_error(title, message):
|
||||||
|
"""Display a notification with the error icon
|
||||||
|
|
||||||
|
:param str title: Title of the notification
|
||||||
|
:param str message: Message of the notification
|
||||||
|
"""
|
||||||
|
xbmcgui.Dialog().notification(heading=title,
|
||||||
|
message=message,
|
||||||
|
icon=xbmcgui.NOTIFICATION_ERROR)
|
||||||
|
|
||||||
|
def notif_info(title, message):
|
||||||
|
"""Display a notification with the info icon
|
||||||
|
|
||||||
|
:param str title: Title of the notification
|
||||||
|
:param str message: Message of the notification
|
||||||
|
"""
|
||||||
|
xbmcgui.Dialog().notification(heading=title,
|
||||||
|
message=message,
|
||||||
|
icon=xbmcgui.NOTIFICATION_INFO)
|
||||||
|
|
||||||
|
def notif_warning(title, message):
|
||||||
|
"""Display a notification with the warning icon
|
||||||
|
|
||||||
|
:param str title: Title of the notification
|
||||||
|
:param str message: Message of the notification
|
||||||
|
"""
|
||||||
|
xbmcgui.Dialog().notification(heading=title,
|
||||||
|
message=message,
|
||||||
|
icon=xbmcgui.NOTIFICATION_WARNING)
|
||||||
|
|
||||||
|
def open_dialog(title, message):
|
||||||
|
"""Open a dialog box with an "OK" button
|
||||||
|
|
||||||
|
:param str title: Title of the box
|
||||||
|
:param str message: Message in the box
|
||||||
|
"""
|
||||||
|
xbmcgui.Dialog().ok(heading=title, line1=message)
|
||||||
|
|
||||||
|
def set_property(name, value):
|
||||||
|
"""Modify the value of a window property related to the add-on
|
||||||
|
|
||||||
|
:param str name: Name of the property which value will be modified (the
|
||||||
|
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)
|
110
service.py
110
service.py
|
@ -1,24 +1,46 @@
|
||||||
import libtorrent
|
# -*- coding: utf-8 -*-
|
||||||
import time, sys
|
"""
|
||||||
import xbmc, xbmcvfs
|
PeerTube service to download torrents in the background
|
||||||
|
|
||||||
|
Copyright (C) 2018 Cyrille Bollu
|
||||||
|
Copyright (C) 2021 Thomas Bétous
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
See LICENSE.txt for more information.
|
||||||
|
"""
|
||||||
|
|
||||||
import AddonSignals
|
import AddonSignals
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
import xbmc
|
||||||
|
import xbmcvfs
|
||||||
|
|
||||||
|
from resources.lib.kodi_utils import debug, set_property
|
||||||
|
|
||||||
class PeertubeDownloader(Thread):
|
class PeertubeDownloader(Thread):
|
||||||
"""
|
"""
|
||||||
A class to download peertube torrents in the background
|
A class to download PeerTube torrents in the background
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, url, temp_dir):
|
def __init__(self, url, temp_dir):
|
||||||
"""
|
"""
|
||||||
Initialise a PeertubeDownloader instance for downloading the torrent specified by url
|
Initialise a PeertubeDownloader instance for downloading the torrent
|
||||||
|
specified by url
|
||||||
|
|
||||||
:param url, temp_dir: str
|
:param url, temp_dir: str
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
Thread.__init__(self)
|
super(PeertubeDownloader, self).__init__(self)
|
||||||
self.torrent = url
|
self.torrent = url
|
||||||
self.temp_dir = temp_dir
|
self.temp_dir = temp_dir
|
||||||
|
|
||||||
|
def debug(self, message):
|
||||||
|
"""Log a debug message
|
||||||
|
|
||||||
|
:param str message: Message to log (will be prefixed with the name of
|
||||||
|
the class)
|
||||||
|
"""
|
||||||
|
debug('PeertubeDownloader: {}'.format(message))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
Download the torrent specified by self.torrent
|
Download the torrent specified by self.torrent
|
||||||
|
@ -26,51 +48,56 @@ class PeertubeDownloader(Thread):
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
xbmc.log('PeertubeDownloader: Opening bitTorent session', xbmc.LOGDEBUG)
|
self.debug('Opening BitTorent session')
|
||||||
# Open bitTorrent session
|
# Open BitTorrent session
|
||||||
ses = libtorrent.session()
|
ses = libtorrent.session()
|
||||||
ses.listen_on(6881, 6891)
|
ses.listen_on(6881, 6891)
|
||||||
|
|
||||||
# Add torrent
|
# Add torrent
|
||||||
xbmc.log('PeertubeDownloader: Adding torrent ' + self.torrent, xbmc.LOGDEBUG)
|
self.debug('Adding torrent {}'.format(self.torrent))
|
||||||
h = ses.add_torrent({'url': self.torrent, 'save_path': self.temp_dir})
|
h = ses.add_torrent({'url': self.torrent, 'save_path': self.temp_dir})
|
||||||
|
|
||||||
# Set sequential mode to allow watching while downloading
|
# Set sequential mode to allow watching while downloading
|
||||||
h.set_sequential_download(True)
|
h.set_sequential_download(True)
|
||||||
|
|
||||||
# Download torrent
|
# Download torrent
|
||||||
xbmc.log('PeertubeDownloader: Downloading torrent ' + self.torrent, xbmc.LOGDEBUG)
|
self.debug('Downloading torrent {}'.format(self.torrent))
|
||||||
signal_sent = 0
|
signal_sent = 0
|
||||||
while not h.is_seed():
|
while not h.is_seed():
|
||||||
xbmc.sleep(1000)
|
xbmc.sleep(1000)
|
||||||
s = h.status()
|
s = h.status()
|
||||||
# Inform addon that all the metadata has been downloaded and that it may start playing the torrent
|
# 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:
|
if s.state >=3 and signal_sent == 0:
|
||||||
xbmc.log('PeertubeDownloader: Received all torrent metadata, notifying PeertubeAddon', xbmc.LOGDEBUG)
|
self.debug('Received all torrent metadata, notifying'
|
||||||
|
' PeertubeAddon')
|
||||||
i = h.torrent_file()
|
i = h.torrent_file()
|
||||||
f = self.temp_dir + i.name()
|
f = self.temp_dir + i.name()
|
||||||
AddonSignals.sendSignal('metadata_downloaded', {'file': f})
|
AddonSignals.sendSignal('metadata_downloaded', {'file': f})
|
||||||
signal_sent = 1
|
signal_sent = 1
|
||||||
|
|
||||||
# Everything is done
|
|
||||||
return
|
|
||||||
|
|
||||||
class PeertubeService():
|
class PeertubeService():
|
||||||
"""
|
"""
|
||||||
|
Class used to run a service when Kodi starts
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
PeertubeService initialisation function
|
PeertubeService initialisation function
|
||||||
"""
|
"""
|
||||||
|
|
||||||
xbmc.log('PeertubeService: Initialising', xbmc.LOGDEBUG)
|
|
||||||
# Create our temporary directory
|
# Create our temporary directory
|
||||||
self.temp = xbmc.translatePath('special://temp') + '/plugin.video.peertube/'
|
self.temp = '{}{}'.format(xbmc.translatePath('special://temp'),
|
||||||
|
'plugin.video.peertube/')
|
||||||
if not xbmcvfs.exists(self.temp):
|
if not xbmcvfs.exists(self.temp):
|
||||||
xbmcvfs.mkdir(self.temp)
|
xbmcvfs.mkdir(self.temp)
|
||||||
|
|
||||||
return
|
def debug(self, message):
|
||||||
|
"""Log a debug message
|
||||||
|
|
||||||
|
:param str message: Message to log (will be prefixed with the name of
|
||||||
|
the class)
|
||||||
|
"""
|
||||||
|
debug('PeertubeService: {}'.format(message))
|
||||||
|
|
||||||
def download_torrent(self, data):
|
def download_torrent(self, data):
|
||||||
"""
|
"""
|
||||||
|
@ -79,35 +106,52 @@ class PeertubeService():
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
xbmc.log('PeertubeService: Received a start_download signal', xbmc.LOGDEBUG)
|
self.debug('Received a start_download signal')
|
||||||
downloader = PeertubeDownloader(data['url'], self.temp)
|
downloader = PeertubeDownloader(data['url'], self.temp)
|
||||||
downloader.start()
|
downloader.start()
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
Main loop of the PeertubeService class, registring the start_download signal to start a
|
Main loop of the PeertubeService class
|
||||||
peertubeDownloader thread when needed, and exit when Kodi is shutting down
|
|
||||||
|
It registers the start_download signal to start a PeertubeDownloader
|
||||||
|
thread when needed, and exit when Kodi is shutting down.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Launch the download_torrent callback function when the 'start_download' signal is received
|
self.debug('Starting')
|
||||||
AddonSignals.registerSlot('plugin.video.peertube', 'start_download', self.download_torrent)
|
|
||||||
|
# Launch the download_torrent callback function when the
|
||||||
|
# 'start_download' signal is received
|
||||||
|
AddonSignals.registerSlot('plugin.video.peertube',
|
||||||
|
'start_download',
|
||||||
|
self.download_torrent)
|
||||||
|
|
||||||
# Monitor Kodi's shutdown signal
|
# Monitor Kodi's shutdown signal
|
||||||
xbmc.log('PeertubeService: service started, Waiting for signals', xbmc.LOGDEBUG)
|
self.debug('Service started, waiting for signals')
|
||||||
monitor = xbmc.Monitor()
|
monitor = xbmc.Monitor()
|
||||||
while not monitor.abortRequested():
|
while not monitor.abortRequested():
|
||||||
if monitor.waitForAbort(1):
|
if monitor.waitForAbort(1):
|
||||||
# Abort was requested while waiting. We must exit
|
# Abort was requested while waiting. We must exit
|
||||||
# TODO: Clean temporary directory
|
# TODO: Clean temporary directory
|
||||||
|
self.debug('Exiting')
|
||||||
break
|
break
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Start a peertubeService instance
|
# Create a PeertubeService instance
|
||||||
xbmc.log('PeertubeService: Starting', xbmc.LOGDEBUG)
|
|
||||||
service = PeertubeService()
|
service = PeertubeService()
|
||||||
|
|
||||||
|
# Import libtorrent here to manage when the library is not installed
|
||||||
|
try:
|
||||||
|
import libtorrent
|
||||||
|
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))
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
# Start the service
|
||||||
service.run()
|
service.run()
|
||||||
xbmc.log('PeertubeService: Exiting', xbmc.LOGDEBUG)
|
|
||||||
|
|
Loading…
Reference in New Issue