diff --git a/addon.xml b/addon.xml index 1224d80..0b801d3 100644 --- a/addon.xml +++ b/addon.xml @@ -9,7 +9,7 @@ video - + Add-on für PeerTube PeerTube ist eine kostenlose, dezentralisierte und föderierte Alternative zu anderen Videoplattformen (wie YouTube). diff --git a/resources/language/resource.language.de_de/strings.po b/resources/language/resource.language.de_de/strings.po index a15b9cf..fbbdb6a 100644 --- a/resources/language/resource.language.de_de/strings.po +++ b/resources/language/resource.language.de_de/strings.po @@ -86,8 +86,8 @@ msgid "PeerTube service started" msgstr "PeerTube-Dienst gestartet" msgctxt "#30401" -msgid "Torrents can now be downloaded." -msgstr "Torrents können jetzt heruntergeladen werden." +msgid "Torrents can now be controlled." +msgstr "" msgctxt "#30402" msgid "Request error" diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 4c61059..da8a7c7 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -86,7 +86,7 @@ msgid "PeerTube service started" msgstr "" msgctxt "#30401" -msgid "Torrents can now be downloaded." +msgid "Torrents can now be controlled." msgstr "" msgctxt "#30402" diff --git a/resources/language/resource.language.fr_fr/strings.po b/resources/language/resource.language.fr_fr/strings.po index 2e4ff0d..6491ca5 100644 --- a/resources/language/resource.language.fr_fr/strings.po +++ b/resources/language/resource.language.fr_fr/strings.po @@ -86,8 +86,8 @@ msgid "PeerTube service started" msgstr "Le service PeerTube a démarré" msgctxt "#30401" -msgid "Torrents can now be downloaded." -msgstr "Les torrents peuvent maintenant être téléchargés." +msgid "Torrents can now be controlled." +msgstr "Les torrents peuvent maintenant être contrôlés." msgctxt "#30402" msgid "Request error" diff --git a/resources/lib/addon.py b/resources/lib/addon.py index b8709d4..465eb9a 100644 --- a/resources/lib/addon.py +++ b/resources/lib/addon.py @@ -15,6 +15,7 @@ from urllib import quote_plus from resources.lib.kodi_utils import kodi from resources.lib.peertube import PeerTube, list_instances +import AddonSignals import xbmcvfs class PeerTubeAddon(): @@ -22,9 +23,6 @@ class PeerTubeAddon(): Main class used by the add-on """ - # URL of the page which explains how to install libtorrent - HELP_URL = "https://link.infini.fr/libtorrent-peertube-kodi" - def __init__(self): """Initialize parameters and create a PeerTube instance""" @@ -40,14 +38,6 @@ class PeerTubeAddon(): self.torrent_name = "" self.torrent_file = "" - # 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 = \ - kodi.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( @@ -349,6 +339,8 @@ class PeerTubeAddon(): vfs_url = "torrent://{}".format(quote_plus(torrent_url)) torrent = xbmcvfs.File(vfs_url) + AddonSignals.sendSignal("get_torrent", {"torrent_url": vfs_url}) + # Download the file if(torrent.write("download")): @@ -366,6 +358,7 @@ class PeerTubeAddon(): # Play the file kodi.debug("Starting video playback of {}".format(self.torrent_file)) kodi.play(self.torrent_file) + else: kodi.notif_error(title=kodi.get_string(30421), message=kodi.get_string(30422)) diff --git a/service.py b/service.py index 7c406b1..2af97e6 100644 --- a/service.py +++ b/service.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ - PeerTube service to download torrents in the background + PeerTube service to perform action on torrents in background Copyright (C) 2018 Cyrille Bollu Copyright (C) 2021 Thomas Bétous @@ -8,73 +8,36 @@ SPDX-License-Identifier: GPL-3.0-only See LICENSE.txt for more information. """ - -import AddonSignals # Module exists only in Kodi - pylint: disable=import-error -from threading import Thread -import xbmc # Kodistubs for Leia is not compatible with python3 / pylint: disable=syntax-error -import xbmcvfs # Kodistubs for Leia is not compatible with python3 / pylint: disable=syntax-error +import AddonSignals +import xbmc +import xbmcvfs from resources.lib.kodi_utils import kodi -class PeertubeDownloader(Thread): - """ - A class to download PeerTube torrents in the background - """ +class PeertubePlayer(xbmc.Player): + # Initialize the attributes and call the parent class constructor + def __init__(self): + self.torrent_url = None + super(xbmc.Player, self).__init__() + # super().__init__() - def __init__(self, url, temp_dir): - """ - Initialise a PeertubeDownloader instance for downloading the torrent - specified by url + # This function will be called through AddonSignals when a video is played. + # It will save the URL expected by vfs.libtorrent to control the torrent. + def receive_torrent(self, data): + self.torrent_url = data["torrent_url"] + kodi.debug(message="Received handle:\n{}".format(self.torrent_url), prefix="PeertubePlayer") - :param url, temp_dir: str - :return: None - """ - Thread.__init__(self) - self.torrent = url - 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) - """ - kodi.debug(message=message, prefix="PeertubeDownloader") - - def run(self): - """ - Download the torrent specified by self.torrent - :param: None - :return: None - """ - - 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}) - - # Set sequential mode to allow watching while downloading - h.set_sequential_download(True) - - # Download torrent - self.debug("Downloading torrent {}".format(self.torrent)) - signal_sent = 0 - while not h.is_seed(): - xbmc.sleep(1000) - s = h.status() - # 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") - i = h.torrent_file() - f = self.temp_dir + i.name() - AddonSignals.sendSignal("metadata_downloaded", {"file": f}) - signal_sent = 1 + # Callback when the playback is stopped. It is used to pause the torrent to + # avoid downloading in background a video which may never be played. + def onPlayBackStopped(self): + if self.torrent_url is not None: + kodi.debug(message="Playback stopped: pausing torrent...", prefix="PeertubePlayer") + # Get the torrent handle + torrent = xbmcvfs.File(self.torrent_url) + # Call seek() to pause the torrent. 0 is used as second argument so + # that GetLength() is not called. + torrent.seek(0, 0) + self.torrent_url = None class PeertubeService(): """ @@ -83,13 +46,10 @@ class PeertubeService(): def __init__(self): """ - PeertubeService initialisation function + Create an instance of PeertubePlayer that will always be active + (required to monitor the events and call the callbacks) """ - # Create our temporary directory - self.temp = "{}{}".format(xbmc.translatePath("special://temp"), - "plugin.video.peertube/") - if not xbmcvfs.exists(self.temp): - xbmcvfs.mkdir(self.temp) + self.player = PeertubePlayer() def debug(self, message): """Log a debug message @@ -99,43 +59,29 @@ class PeertubeService(): """ kodi.debug(message=message, prefix="PeertubeService") - def download_torrent(self, data): - """ - 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) - downloader.start() - def run(self): """ Main loop of the PeertubeService class - It registers the start_download signal to start a PeertubeDownloader - thread when needed, and exit when Kodi is shutting down. """ - self.debug("Starting") - - # Launch the download_torrent callback function when the - # "start_download" signal is received + # Signal that is sent by the main script of the add-on AddonSignals.registerSlot(kodi.addon_id, - "start_download", - self.download_torrent) + "get_torrent", + self.player.receive_torrent) - # Monitor Kodi's shutdown signal - self.debug("Service started, waiting for signals") + + # Display a notification now that the service started. + self.debug("Service started") if kodi.get_setting("service_start_notif") == "true": kodi.notif_info(title=kodi.get_string(30400), message=kodi.get_string(30401)) + + # Run the service until Kodi exits monitor = xbmc.Monitor() while not monitor.abortRequested(): if monitor.waitForAbort(1): - # Abort was requested while waiting. We must exit - # TODO: Clean temporary directory + # Abort was requested while waiting. We must exit. self.debug("Exiting") break @@ -143,18 +89,5 @@ if __name__ == "__main__": # Create a PeertubeService instance service = PeertubeService() - # Import libtorrent here to manage when the library is not installed - try: - from python_libtorrent 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 - kodi.set_property("libtorrent_imported", str(LIBTORRENT_IMPORTED)) - # Start the service service.run()