рабочая версия плагина
This commit is contained in:
		
							parent
							
								
									5a640c4ae4
								
							
						
					
					
						commit
						ca2a815140
					
				| @ -1,8 +1,7 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||||||
| <addon id="script.module.pyrrent2http" name="pyrrent2http" version="1.1.1" provider-name="inpos"> | <addon id="script.module.gorrent2http" name="gorrent2http" version="1.0.0" provider-name="inpos"> | ||||||
|     <requires> |     <requires> | ||||||
|         <import addon="xbmc.python" version="3.0.0"/> |         <import addon="xbmc.python" version="3.0.0"/> | ||||||
|         <import	addon="script.module.libtorrent" version="1.2.0"/> |  | ||||||
|         <import addon="script.module.chardet" /> |         <import addon="script.module.chardet" /> | ||||||
|     </requires> |     </requires> | ||||||
|     <extension point="xbmc.python.module" library="lib"/> |     <extension point="xbmc.python.module" library="lib"/> | ||||||
| @ -17,5 +16,5 @@ | |||||||
|         <description lang="ru">Обеспечивает последовательную (sequential) загрузку торрентов для потокового онлайн просмотра через HTTP. Основан на библиотеке LibTorrent.</description> |         <description lang="ru">Обеспечивает последовательную (sequential) загрузку торрентов для потокового онлайн просмотра через HTTP. Основан на библиотеке LibTorrent.</description> | ||||||
|         <description lang="en">Provides sequential torrent downloading for online streaming video and other media over HTTP.</description> |         <description lang="en">Provides sequential torrent downloading for online streaming video and other media over HTTP.</description> | ||||||
|         <email>inpos@yandex.ru</email> |         <email>inpos@yandex.ru</email> | ||||||
|         <source>https://git.ukamnya.ru/ukamnya/script.module.pyrrent2http</source></extension> |         <source>https://git.ukamnya.ru/ukamnya/script.module.gorrent2http</source></extension> | ||||||
| </addon> | </addon> | ||||||
|  | |||||||
| @ -5,30 +5,45 @@ import urllib.error | |||||||
| import urllib.parse | import urllib.parse | ||||||
| import urllib.request | import urllib.request | ||||||
| 
 | 
 | ||||||
| import chardet |  | ||||||
| import sys | import sys | ||||||
| import time | import time | ||||||
| import xbmc | import xbmc | ||||||
|  | import xbmcvfs | ||||||
|  | from . import log as logging | ||||||
| 
 | 
 | ||||||
| from . import SessionStatus, FileStatus, PeerInfo | from . import FileStatus, SessionStatus | ||||||
| from . import pyrrent2http |  | ||||||
| from .error import Error | from .error import Error | ||||||
| from .structs import Encryption | from .structs import Encryption | ||||||
| from .util import can_bind, find_free_port, localize_path, uri2path, detect_media_type | from .util import can_bind, find_free_port, localize_path, uri2path, detect_media_type, get_platform | ||||||
|  | 
 | ||||||
|  | platform = get_platform() | ||||||
|  | dirname = os.path.join(xbmcvfs.translatePath('special://temp'), 'xbmcup', 'script.module.gorrent2http') | ||||||
|  | dest_path = os.path.join(dirname, platform['system']) | ||||||
|  | sys.path.insert(0, dest_path) | ||||||
|  | 
 | ||||||
|  | try: | ||||||
|  |     from gorrent import gorrent as gt | ||||||
|  | 
 | ||||||
|  |     logging.info(f'Imported gorrent v{gt.Version()}') | ||||||
|  | except Exception: | ||||||
|  |     import traceback | ||||||
|  | 
 | ||||||
|  |     logging.error(f'Error importing gorrent. Exception: {traceback.format_exc()}') | ||||||
|  |     raise | ||||||
| 
 | 
 | ||||||
| LOGGING = True | LOGGING = True | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Engine: | class Engine: | ||||||
|     """ |     """ | ||||||
|     This is python binding class to pyrrent2http client. |     This is python binding class to gorrent2http client. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def _log(self, message): |     def _log(self, message): | ||||||
|         if self.logger: |         if self.logger: | ||||||
|             self.logger(message) |             self.logger(message) | ||||||
|         else: |         else: | ||||||
|             xbmc.log("[pyrrent2http] %s" % message) |             xbmc.log("[gorrent2http] %s" % message) | ||||||
| 
 | 
 | ||||||
|     def __init__(self, uri=None, platform=None, download_path=".", |     def __init__(self, uri=None, platform=None, download_path=".", | ||||||
|                  bind_host='127.0.0.1', bind_port=5001, connections_limit=200, download_kbps=-1, upload_kbps=-1, |                  bind_host='127.0.0.1', bind_port=5001, connections_limit=200, download_kbps=-1, upload_kbps=-1, | ||||||
| @ -45,7 +60,6 @@ class Engine: | |||||||
|         start() method. |         start() method. | ||||||
| 
 | 
 | ||||||
|         :param uri: Torrent URI (magnet://, file:// or http://) |         :param uri: Torrent URI (magnet://, file:// or http://) | ||||||
|         :param binaries_path: Path to torrent2http binaries |  | ||||||
|         :param platform: Object with two methods implemented: arch() and system() |         :param platform: Object with two methods implemented: arch() and system() | ||||||
|         :param download_path: Torrent download path |         :param download_path: Torrent download path | ||||||
|         :param bind_host: Bind host of torrent2http |         :param bind_host: Bind host of torrent2http | ||||||
| @ -134,16 +148,12 @@ class Engine: | |||||||
|         self.started = False |         self.started = False | ||||||
|         self.proxy = proxy |         self.proxy = proxy | ||||||
| 
 | 
 | ||||||
|  |         self.message_logger = None | ||||||
|  |         self.run_message_logger = True | ||||||
|  | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _validate_save_path(path): |     def _validate_save_path(path): | ||||||
|         """ |         path = xbmcvfs.translatePath(path) | ||||||
|         Ensures download path can be accessed locally. |  | ||||||
| 
 |  | ||||||
|         :param path: Download path |  | ||||||
|         :return: Translated path |  | ||||||
|         """ |  | ||||||
|         import xbmc |  | ||||||
|         path = xbmc.translatePath(path) |  | ||||||
|         if "://" in path: |         if "://" in path: | ||||||
|             if sys.platform.startswith('win') and path.lower().startswith("smb://"): |             if sys.platform.startswith('win') and path.lower().startswith("smb://"): | ||||||
|                 path = path.replace("smb:", "").replace("/", "\\") |                 path = path.replace("smb:", "").replace("/", "\\") | ||||||
| @ -153,67 +163,16 @@ class Engine: | |||||||
|             raise Error("Download path doesn't exist (%s)" % path, Error.INVALID_DOWNLOAD_PATH) |             raise Error("Download path doesn't exist (%s)" % path, Error.INVALID_DOWNLOAD_PATH) | ||||||
|         return localize_path(path) |         return localize_path(path) | ||||||
| 
 | 
 | ||||||
|     def start(self, start_index=None): |     def start(self, start_index): | ||||||
|         """ |  | ||||||
|         Starts pyrrent2http client with specified settings. If it can be started in startup_timeout seconds, exception |  | ||||||
|         will be raised. |  | ||||||
| 
 |  | ||||||
|         :param start_index: File index to start download instantly, if not specified, downloading will be paused, until |  | ||||||
|             any file requested |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|         download_path = self._validate_save_path(self.download_path) |         download_path = self._validate_save_path(self.download_path) | ||||||
|         if not can_bind(self.bind_host, self.bind_port): |         if not can_bind(self.bind_host, self.bind_port): | ||||||
|             port = find_free_port(self.bind_host) |             port = find_free_port(self.bind_host) | ||||||
|             if port is False: |             if port is False: | ||||||
|                 raise Error("Can't find port to bind pyrrent2http", Error.BIND_ERROR) |                 raise Error("Can't find port to bind gorrent2http", Error.BIND_ERROR) | ||||||
|             self._log("Can't bind to %s:%s, so we found another port: %d" % (self.bind_host, self.bind_port, port)) |             self._log("Can't bind to %s:%s, so we found another port: %d" % (self.bind_host, self.bind_port, port)) | ||||||
|             self.bind_port = port |             self.bind_port = port | ||||||
| 
 | 
 | ||||||
|         kwargs = { |         self._log("Invoking gorrent2http") | ||||||
|             'torrentConnectBoost': self.torrent_connect_boost, |  | ||||||
|             'trackers': ",".join(self.trackers), |  | ||||||
|             'proxy': self.proxy, |  | ||||||
|             'resumeFile': self.resume_file, |  | ||||||
|             'minReconnectTime': self.min_reconnect_time, |  | ||||||
|             'enableUPNP': self.enable_upnp, |  | ||||||
|             'showAllStats': self.log_stats, |  | ||||||
|             'debugAlerts': self.debug_alerts, |  | ||||||
|             'keepComplete': self.keep_complete, |  | ||||||
|             'dhtRouters': ",".join(self.dht_routers), |  | ||||||
|             'userAgent': self.user_agent, |  | ||||||
|             'enableLSD': self.enable_lsd, |  | ||||||
|             'uri': self.uri, |  | ||||||
|             'randomPort': self.use_random_port, |  | ||||||
|             'noSparseFile': self.no_sparse, |  | ||||||
|             'maxUploadRate': self.upload_kbps, |  | ||||||
|             'downloadPath': download_path, |  | ||||||
|             'showOverallProgress': self.log_overall_progress, |  | ||||||
|             'enableDHT': self.enable_dht, |  | ||||||
|             'showFilesProgress': self.log_files_progress, |  | ||||||
|             'requestTimeout': self.request_timeout, |  | ||||||
|             'bindAddress': "%s:%s" % (self.bind_host, self.bind_port), |  | ||||||
|             'maxDownloadRate': self.download_kbps, |  | ||||||
|             'connectionSpeed': self.connection_speed, |  | ||||||
|             'keepIncomplete': self.keep_incomplete, |  | ||||||
|             'enableTCP': self.enable_tcp, |  | ||||||
|             'listenPort': self.listen_port, |  | ||||||
|             'keepFiles': self.keep_files, |  | ||||||
|             'stateFile': self.state_file, |  | ||||||
|             'peerConnectTimeout': self.peer_connect_timeout, |  | ||||||
|             'maxFailCount': self.max_failcount, |  | ||||||
|             'showPiecesProgress': self.log_pieces_progress, |  | ||||||
|             'idleTimeout': self.max_idle_timeout, |  | ||||||
|             # 'fileIndex': start_index, |  | ||||||
|             'connectionsLimit': self.connections_limit, |  | ||||||
|             'enableScrape': self.enable_scrape, |  | ||||||
|             'enableUTP': self.enable_utp, |  | ||||||
|             'encryption': self.encryption, |  | ||||||
|             'enableNATPMP': self.enable_natpmp |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         self._log("Invoking pyrrent2http") |  | ||||||
| 
 | 
 | ||||||
|         class Logging(object): |         class Logging(object): | ||||||
|             def __init__(self, _log): |             def __init__(self, _log): | ||||||
| @ -227,15 +186,34 @@ class Engine: | |||||||
|                 if LOGGING: |                 if LOGGING: | ||||||
|                     self._log('ERROR: %s' % (message,)) |                     self._log('ERROR: %s' % (message,)) | ||||||
| 
 | 
 | ||||||
|         pyrrent2http.logging = Logging(self._log) |         gt.logging = Logging(self._log) | ||||||
| 
 | 
 | ||||||
|         self.pyrrent2http = pyrrent2http.Pyrrent2http(**kwargs) |         settings = gt.NewSettings() | ||||||
|         self.pyrrent2http.startSession() |         settings.DownloadPath = download_path | ||||||
|         self.pyrrent2http.startServices() |         settings.HttpBindHost = self.bind_host | ||||||
|         self.pyrrent2http.addTorrent() |         settings.HttpBindPort = self.bind_port | ||||||
|         self.pyrrent2http.startHTTP() |         settings.ListenPort = self.listen_port | ||||||
|         self.pyrrent2http_loop = threading.Thread(target=self.pyrrent2http.loop) |         settings.TorrentPath = uri2path(self.uri) | ||||||
|         self.pyrrent2http_loop.start() |         settings.MaxConnections = self.connections_limit | ||||||
|  |         settings.Debug = self.debug_alerts | ||||||
|  |         settings.KeepFiles = self.keep_files | ||||||
|  |         settings.Proxy = len(self.proxy) > 0 and f'socks5://{self.proxy["host"]}:{self.proxy["port"]}' or '' | ||||||
|  | 
 | ||||||
|  |         self.engine = gt.NewEngine(settings) | ||||||
|  |         def msg_logger(): | ||||||
|  |             while self.run_message_logger: | ||||||
|  |                 msg = self.engine.GetMsg() | ||||||
|  |                 if msg not in ('__NO_MSG__', '__CLOSED__'): | ||||||
|  |                     xbmc.log(f'-= GORRENT =-: {msg}') | ||||||
|  |                 time.sleep(0.1) | ||||||
|  |         self.message_logger = threading.Thread(target=msg_logger) | ||||||
|  |         self.message_logger.start() | ||||||
|  | 
 | ||||||
|  |         self._log('starting torrent') | ||||||
|  | 
 | ||||||
|  |         self.engine.StartTorrent(start_index) | ||||||
|  | 
 | ||||||
|  |         self._log('waiting alive status set') | ||||||
| 
 | 
 | ||||||
|         start = time.time() |         start = time.time() | ||||||
|         self.started = True |         self.started = True | ||||||
| @ -243,7 +221,7 @@ class Engine: | |||||||
|         while (time.time() - start) < self.startup_timeout: |         while (time.time() - start) < self.startup_timeout: | ||||||
|             time.sleep(0.1) |             time.sleep(0.1) | ||||||
|             if not self.is_alive(): |             if not self.is_alive(): | ||||||
|                 raise Error("Can't start pyrrent2http, see log for details", Error.PROCESS_ERROR) |                 raise Error("Can't start gorrent2http, see log for details", Error.PROCESS_ERROR) | ||||||
|             try: |             try: | ||||||
|                 # self.status(1) |                 # self.status(1) | ||||||
|                 initialized = True |                 initialized = True | ||||||
| @ -253,79 +231,77 @@ class Engine: | |||||||
| 
 | 
 | ||||||
|         if not initialized: |         if not initialized: | ||||||
|             self.started = False |             self.started = False | ||||||
|             raise Error("Can't start pyrrent2http, time is out", Error.TIMEOUT) |             raise Error("Can't start gorrent2http, time is out", Error.TIMEOUT) | ||||||
|         self._log("pyrrent2http successfully started.") |         self._log("gorrent2http successfully started.") | ||||||
| 
 |  | ||||||
|     def activate_file(self, index): |  | ||||||
|         self.pyrrent2http.TorrentFS.file(index) |  | ||||||
| 
 | 
 | ||||||
|     def pause(self): |     def pause(self): | ||||||
|         self.pyrrent2http.pause = True |         pass | ||||||
| 
 | 
 | ||||||
|     def resume(self): |     def resume(self): | ||||||
|         self.pyrrent2http.pause = False |         pass | ||||||
| 
 | 
 | ||||||
|     def check_torrent_error(self, status=None): |     def check_torrent_error(self, status=None): | ||||||
|         """ |  | ||||||
|         It is recommended to call this method periodically to check if any libtorrent errors occurred. |  | ||||||
|         Usually libtorrent sets error if it can't download or parse torrent file by specified URI. |  | ||||||
|         Note that pyrrent2http remains started after such error, so you need to shutdown it manually. |  | ||||||
| 
 |  | ||||||
|         :param status: Pass return of status() method if you don't want status() called twice |  | ||||||
|         """ |  | ||||||
|         if not status: |         if not status: | ||||||
|             status = self.status() |             status = self.status() | ||||||
|         if status.error: |         if status.error: | ||||||
|             raise Error("Torrent error: %s" % status.error, Error.TORRENT_ERROR, reason=status.error) |             raise Error("Torrent error: %s" % status.error, Error.TORRENT_ERROR, reason=status.error) | ||||||
| 
 | 
 | ||||||
|     def status(self, timeout=10): |     def status(self, timeout=10): | ||||||
|         """ |         stat = self.engine.Status() | ||||||
|         Returns libtorrent session status. See SessionStatus named tuple. |         stat_kw = { | ||||||
| 
 |             'download_rate': stat.DownloadRate, | ||||||
|         :rtype : SessionStatus |             'upload_rate': stat.UploadRate, | ||||||
|         :param timeout: pyrrent2http client request timeout |             'num_seeds': stat.Seeds, | ||||||
|         """ |             'name': '', | ||||||
|         status = self.pyrrent2http.Status() |             'state': 0, | ||||||
|         status = SessionStatus(**status) |             'state_str': '', | ||||||
|         return status |             'error': '', | ||||||
| 
 |             'progress': 0, | ||||||
|     def list(self, media_types=None, timeout=10): |             'total_download': 0, | ||||||
|         """ |             'total_upload': 0, | ||||||
|         Returns list of files in the torrent (see FileStatus named tuple). |             'num_peers': 0, | ||||||
|         Note that it will return None if torrent file is not loaded yet by pyrrent2http client, so you may need to call |             'total_seeds': 0, | ||||||
|         this method periodically until results are returned. |             'total_peers': 0 | ||||||
| 
 |         } | ||||||
|         :param media_types: List of media types (see MediaType constants) |         return SessionStatus(**stat_kw) | ||||||
|         :param timeout: pyrrent2http client request timeout |  | ||||||
|         :rtype : list of FileStatus |  | ||||||
|         :return: List of files of specified media types or None if torrent is not loaded yet |  | ||||||
|         """ |  | ||||||
|         files = self.pyrrent2http.Ls()['files'] |  | ||||||
|         if files: |  | ||||||
|             res = [FileStatus(index=index, **f) for index, f in enumerate(files)] |  | ||||||
|             if media_types is not None: |  | ||||||
|                 res = [fs for fs in res if fs.media_type in media_types] |  | ||||||
|             return res |  | ||||||
| 
 | 
 | ||||||
|     def list_from_info(self, media_types=None): |     def list_from_info(self, media_types=None): | ||||||
|         try: |         try: | ||||||
|             info = pyrrent2http.lt.torrent_info(uri2path(self.uri)) |             info = gt.GetMetaFromFile(uri2path(self.uri)) | ||||||
|         except: |         except: | ||||||
|  |             import traceback | ||||||
|  |             xbmc.log(f'info load exception: {traceback.format_exc()}') | ||||||
|             return [] |             return [] | ||||||
|         files = [] |         files = [] | ||||||
|         for i in range(info.num_files()): |         if len(info.Files) > 0: | ||||||
|             f = info.file_at(i) |             for i in range(len(info.Files)): | ||||||
|             Url = 'http://' + "%s:%s" % (self.bind_host, self.bind_port) + '/files/' + urllib.parse.quote(f.path) |                 f = info.Files[i] | ||||||
|  | 
 | ||||||
|  |                 uri = 'http://' + "%s:%s" % (self.bind_host, self.bind_port) + '/files/' + urllib.parse.quote( | ||||||
|  |                     '/'.join(f.Path)) | ||||||
|                 files.append({ |                 files.append({ | ||||||
|                 'name': localize_path(f.path), |                     'name': localize_path('/'.join(f.Path)), | ||||||
|                 'size': f.size, |                     'size': f.Length, | ||||||
|                 'offset': f.offset, |                     'offset': i, | ||||||
|                 'media_type': media_types is not None and detect_media_type(f.path) or '', |                     'media_type': media_types is not None and detect_media_type(f.Path[-1]) or '', | ||||||
|                     'download': 0, |                     'download': 0, | ||||||
|                     'progress': 0.0, |                     'progress': 0.0, | ||||||
|                     'save_path': '', |                     'save_path': '', | ||||||
|                 'url': Url |                     'url': uri | ||||||
|                 }) |                 }) | ||||||
|  |         else: | ||||||
|  |             files.append({ | ||||||
|  |                 'name': localize_path(info.Name), | ||||||
|  |                 'size': info.Length, | ||||||
|  |                 'offset': 0, | ||||||
|  |                 'media_type': media_types is not None and detect_media_type(info.Name) or '', | ||||||
|  |                 'download': 0, | ||||||
|  |                 'progress': 0.0, | ||||||
|  |                 'save_path': '', | ||||||
|  |                 'url': 'http://' + "%s:%s" % (self.bind_host, self.bind_port) + '/files/' + urllib.parse.quote( | ||||||
|  |                     info.Name) | ||||||
|  |             }) | ||||||
|  |         res = [] | ||||||
|         if len(files) > 0: |         if len(files) > 0: | ||||||
|             res = [FileStatus(index=index, **f) for index, f in enumerate(files)] |             res = [FileStatus(index=index, **f) for index, f in enumerate(files)] | ||||||
|         if media_types is not None: |         if media_types is not None: | ||||||
| @ -333,57 +309,34 @@ class Engine: | |||||||
|         return res |         return res | ||||||
| 
 | 
 | ||||||
|     def file_status(self, file_index, timeout=10): |     def file_status(self, file_index, timeout=10): | ||||||
|         """ |  | ||||||
|         Returns file in the torrent with specified index (see FileStatus named tuple) |  | ||||||
|         Note that it will return None if torrent file is not loaded yet by pyrrent2http client, so you may need to call |  | ||||||
|         this method periodically until results are returned. |  | ||||||
| 
 |  | ||||||
|         :param file_index: Requested file's index |  | ||||||
|         :param timeout: pyrrent2http client request timeout |  | ||||||
|         :return: File with specified index |  | ||||||
|         :rtype: FileStatus |  | ||||||
|         """ |  | ||||||
|         filestatus = self.pyrrent2http.Ls(file_index) |  | ||||||
|         try: |         try: | ||||||
|             return FileStatus(**filestatus) |             efs = self.engine.FileStatus(file_index) | ||||||
|  |             fstat = { | ||||||
|  |                 'name': localize_path('/'.join(efs.Name)), | ||||||
|  |                 'progress': efs.Progress, | ||||||
|  |                 'url': efs.Url, | ||||||
|  |                 'save_path': '', | ||||||
|  |                 'size': efs.Length, | ||||||
|  |                 'offset': 0, | ||||||
|  |                 'download': 0, | ||||||
|  |                 'media_type': '' | ||||||
|  |             } | ||||||
|  |             return FileStatus(index=file_index, **fstat) | ||||||
|         except: |         except: | ||||||
|             raise Error("Requested file index (%d) is invalid" % (file_index,), Error.INVALID_FILE_INDEX, |             raise Error("Requested file index (%d) is invalid" % (file_index,), Error.INVALID_FILE_INDEX, | ||||||
|                         file_index=file_index) |                         file_index=file_index) | ||||||
| 
 | 
 | ||||||
|     def peers(self, timeout=10): |  | ||||||
|         """ |  | ||||||
|         Returns list of peers connected (see PeerInfo named tuple). |  | ||||||
| 
 |  | ||||||
|         :param timeout: pyrrent2http client request timeout |  | ||||||
|         :return: List of peers |  | ||||||
|         :rtype: list of PeerInfo |  | ||||||
|         """ |  | ||||||
|         peers = self.pyrrent2http.Peers()['peers'] |  | ||||||
|         if peers: |  | ||||||
|             return [PeerInfo(**p) for p in peers] |  | ||||||
| 
 |  | ||||||
|     def is_alive(self): |     def is_alive(self): | ||||||
|         return self.pyrrent2http_loop.is_alive() |         return self.engine.IsAlive() | ||||||
| 
 |  | ||||||
|     def wait_on_close(self, wait_timeout=10): |  | ||||||
|         """ |  | ||||||
|         By default, close() method sends shutdown command to pyrrent2http, stops logging and returns immediately, not |  | ||||||
|         waiting while pyrrent2http exits. It can be handy to wait pyrrent2http to view log messages during shutdown. |  | ||||||
|         So call this method with reasonable timeout before calling close(). |  | ||||||
| 
 |  | ||||||
|         :param wait_timeout: Time in seconds to wait until pyrrent2http client shut down |  | ||||||
|         """ |  | ||||||
|         self.wait_on_close_timeout = wait_timeout |  | ||||||
| 
 | 
 | ||||||
|     def close(self): |     def close(self): | ||||||
|         """ |  | ||||||
|         Shuts down pyrrent2http and stops logging. If wait_on_close() was called earlier, it will wait until |  | ||||||
|         pyrrent2http successfully exits. |  | ||||||
|         """ |  | ||||||
|         if self.is_alive(): |         if self.is_alive(): | ||||||
|             self._log("Shutting down pyrrent2http...") |             self._log("Shutting down gorrent2http...") | ||||||
|             self.pyrrent2http.shutdown() |             self.engine.Stop() | ||||||
|             finished = False |             finished = False | ||||||
|  | 
 | ||||||
|  |             self.wait_on_close_timeout = 10 | ||||||
|  | 
 | ||||||
|             if self.wait_on_close_timeout is not None: |             if self.wait_on_close_timeout is not None: | ||||||
|                 start = time.time() |                 start = time.time() | ||||||
|                 while (time.time() - start) < self.wait_on_close_timeout: |                 while (time.time() - start) < self.wait_on_close_timeout: | ||||||
| @ -392,11 +345,12 @@ class Engine: | |||||||
|                         finished = True |                         finished = True | ||||||
|                         break |                         break | ||||||
|                 if not finished: |                 if not finished: | ||||||
|                     self._log("PANIC: Timeout occurred while shutting down pyrrent2http thread") |                     self._log("PANIC: Timeout occurred while shutting down gorrent2http thread") | ||||||
|                 else: |                 else: | ||||||
|                     self._log("pyrrent2http successfully shut down.") |                     self._log("gorrent2http successfully shut down.") | ||||||
|                 self.wait_on_close_timeout = None |                 self.wait_on_close_timeout = None | ||||||
|             self._log("pyrrent2http successfully shut down.") |             self._log("gorrent2http successfully shut down.") | ||||||
|  |         if self.message_logger is not None and self.message_logger.is_alive(): | ||||||
|  |             self.run_message_logger = False | ||||||
|  |         self.message_logger = None | ||||||
|         self.started = False |         self.started = False | ||||||
|         self.logpipe = None |  | ||||||
|         self.process = None |  | ||||||
| @ -1,30 +1,38 @@ | |||||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||||
| import os |  | ||||||
| import chardet |  | ||||||
| 
 |  | ||||||
| try: |  | ||||||
|     from python_libtorrent import get_libtorrent  # @UnresolvedImport |  | ||||||
| 
 |  | ||||||
|     lt = get_libtorrent() |  | ||||||
|     print(('Imported libtorrent v%s from python_libtorrent' % (lt.version,))) |  | ||||||
| except Exception as e: |  | ||||||
|     print(('Error importing python_libtorrent.Exception: %s' % (str(e),))) |  | ||||||
|     try: |  | ||||||
|         import libtorrent as lt  # @UnresolvedImport |  | ||||||
|     except Exception as e: |  | ||||||
|         strerror = e.args |  | ||||||
|         print(strerror) |  | ||||||
|         raise |  | ||||||
| 
 |  | ||||||
| from random import SystemRandom |  | ||||||
| import time |  | ||||||
| import urllib.request, urllib.parse, urllib.error |  | ||||||
| import http.server | import http.server | ||||||
|  | import io | ||||||
|  | import os | ||||||
| import socketserver | import socketserver | ||||||
| import threading | import threading | ||||||
| import io | import urllib.error | ||||||
|  | import urllib.parse | ||||||
|  | import urllib.request | ||||||
|  | from random import SystemRandom | ||||||
|  | from . import log as logging | ||||||
|  | 
 | ||||||
|  | import chardet | ||||||
|  | import sys | ||||||
|  | import time | ||||||
|  | import xbmc | ||||||
|  | import xbmcvfs | ||||||
|  | 
 | ||||||
|  | from . import util | ||||||
| from .util import localize_path, Struct, detect_media_type, uri2path, encode_msg | from .util import localize_path, Struct, detect_media_type, uri2path, encode_msg | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | platform = util.get_platform() | ||||||
|  | dirname = os.path.join(xbmcvfs.translatePath('special://temp'), 'xbmcup', 'script.module.gorrent2http') | ||||||
|  | dest_path = os.path.join(dirname, platform['system']) | ||||||
|  | sys.path.insert(0, dest_path) | ||||||
|  | 
 | ||||||
|  | try: | ||||||
|  |     from gorrent import gorrent as gt | ||||||
|  |     logging.info(f'Imported gorrent v{gt.Version()}') | ||||||
|  | except Exception: | ||||||
|  |     import traceback | ||||||
|  |     logging.error(f'Error importing gorrent. Exception: {traceback.format_exc()}') | ||||||
|  |     raise | ||||||
|  | 
 | ||||||
| if os.getenv('ANDROID_ROOT'): | if os.getenv('ANDROID_ROOT'): | ||||||
|     from ctypes import * |     from ctypes import * | ||||||
| 
 | 
 | ||||||
| @ -72,9 +80,9 @@ if not hasattr(os, 'getppid'): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def getppid(): |     def getppid(): | ||||||
|         ''' |         """ | ||||||
|         :return: The pid of the parent of this process. |         :return: The pid of the parent of this process. | ||||||
|         ''' |         """ | ||||||
|         pe = PROCESSENTRY32() |         pe = PROCESSENTRY32() | ||||||
|         pe.dwSize = ctypes.sizeof(PROCESSENTRY32) |         pe.dwSize = ctypes.sizeof(PROCESSENTRY32) | ||||||
|         mypid = GetCurrentProcessId() |         mypid = GetCurrentProcessId() | ||||||
| @ -162,7 +170,8 @@ class TorrentFile(object): | |||||||
|         self.tfs = tfs |         self.tfs = tfs | ||||||
|         self.fileEntry = fileEntry |         self.fileEntry = fileEntry | ||||||
|         self.name = self.fileEntry.path |         self.name = self.fileEntry.path | ||||||
|         self.unicode_name = isinstance(self.name, str) and self.name or self.name.decode(chardet.detect(self.name)['encoding']) |         self.unicode_name = isinstance(self.name, str) and self.name or self.name.decode( | ||||||
|  |             chardet.detect(self.name)['encoding']) | ||||||
|         self.media_type = detect_media_type(self.unicode_name) |         self.media_type = detect_media_type(self.unicode_name) | ||||||
|         self.save_path = savePath |         self.save_path = savePath | ||||||
|         self.index = index |         self.index = index | ||||||
| @ -183,7 +192,7 @@ class TorrentFile(object): | |||||||
|             return None |             return None | ||||||
|         if self.filePtr is None: |         if self.filePtr is None: | ||||||
|             while not os.path.exists(self.save_path): |             while not os.path.exists(self.save_path): | ||||||
|                 logging.info('Waiting for file: %s' % (self.save_path,)) |                 xbmc.log('INFO: Waiting for file: %s' % (self.save_path,)) | ||||||
|                 self.tfs.handle.flush_cache() |                 self.tfs.handle.flush_cache() | ||||||
|                 time.sleep(0.5) |                 time.sleep(0.5) | ||||||
|             if os.getenv('ANDROID_ROOT'): |             if os.getenv('ANDROID_ROOT'): | ||||||
| @ -194,7 +203,7 @@ class TorrentFile(object): | |||||||
| 
 | 
 | ||||||
|     def log(self, message): |     def log(self, message): | ||||||
|         fnum = self.tfs.openedFiles.index(self) |         fnum = self.tfs.openedFiles.index(self) | ||||||
|         logging.info("[Thread No.%d] %s\n" % (fnum, message)) |         xbmc.log("INFO: [Thread No.%d] %s\n" % (fnum, message)) | ||||||
| 
 | 
 | ||||||
|     def Pieces(self): |     def Pieces(self): | ||||||
|         startPiece, _ = self.pieceFromOffset(1) |         startPiece, _ = self.pieceFromOffset(1) | ||||||
| @ -545,10 +554,10 @@ def HttpHandlerFactory(): | |||||||
|     return HttpHandler |     return HttpHandler | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Pyrrent2http(object): | class Gorrent2http(object): | ||||||
|     pause = False |     pause = False | ||||||
| 
 | 
 | ||||||
|     def __init__(self, uri='', bindAddress='localhost:5001', downloadPath='.', |     def __init__(self, uri='', bind_address='localhost:5001', download_path='.', | ||||||
|                  idleTimeout=-1, keepComplete=False, |                  idleTimeout=-1, keepComplete=False, | ||||||
|                  keepIncomplete=False, keepFiles=False, showAllStats=False, |                  keepIncomplete=False, keepFiles=False, showAllStats=False, | ||||||
|                  showOverallProgress=False, showFilesProgress=False, |                  showOverallProgress=False, showFilesProgress=False, | ||||||
| @ -568,8 +577,8 @@ class Pyrrent2http(object): | |||||||
| 
 | 
 | ||||||
|         self.config = Struct() |         self.config = Struct() | ||||||
|         self.config.uri = uri |         self.config.uri = uri | ||||||
|         self.config.bindAddress = bindAddress |         self.config.bindAddress = bind_address | ||||||
|         self.config.downloadPath = downloadPath |         self.config.downloadPath = download_path | ||||||
|         self.config.idleTimeout = idleTimeout |         self.config.idleTimeout = idleTimeout | ||||||
|         self.config.keepComplete = keepComplete |         self.config.keepComplete = keepComplete | ||||||
|         self.config.keepIncomplete = keepIncomplete |         self.config.keepIncomplete = keepIncomplete | ||||||
| @ -618,7 +627,7 @@ class Pyrrent2http(object): | |||||||
|         try: |         try: | ||||||
|             absPath = uri2path(uri) |             absPath = uri2path(uri) | ||||||
|             logging.info('Opening local torrent file: %s' % (encode_msg(absPath),)) |             logging.info('Opening local torrent file: %s' % (encode_msg(absPath),)) | ||||||
|             torrent_info = lt.torrent_info(lt.bdecode(open(absPath, 'rb').read())) |             torrent_info = gt.torrent_info(gt.bdecode(open(absPath, 'rb').read())) | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             strerror = e.args |             strerror = e.args | ||||||
|             logging.error('Build torrent params error is (%s)' % (strerror,)) |             logging.error('Build torrent params error is (%s)' % (strerror,)) | ||||||
| @ -639,7 +648,7 @@ class Pyrrent2http(object): | |||||||
|                 logging.error(strerror) |                 logging.error(strerror) | ||||||
|         if self.config.noSparseFile or self.magnet: |         if self.config.noSparseFile or self.magnet: | ||||||
|             logging.info('Disabling sparse file support...') |             logging.info('Disabling sparse file support...') | ||||||
|             torrentParams["storage_mode"] = lt.storage_mode_t.storage_mode_allocate |             torrentParams["storage_mode"] = gt.storage_mode_t.storage_mode_allocate | ||||||
|         return torrentParams |         return torrentParams | ||||||
| 
 | 
 | ||||||
|     def addTorrent(self): |     def addTorrent(self): | ||||||
| @ -704,14 +713,14 @@ class Pyrrent2http(object): | |||||||
| 
 | 
 | ||||||
|     def startSession(self): |     def startSession(self): | ||||||
|         logging.info('Starting session...') |         logging.info('Starting session...') | ||||||
|         self.session = lt.session(lt.fingerprint('LT', lt.version_major, lt.version_minor, 0, 0), |         self.session = gt.session(gt.fingerprint('LT', gt.version_major, gt.version_minor, 0, 0), | ||||||
|                                   flags=int(lt.session_flags_t.add_default_plugins)) |                                   flags=int(gt.session_flags_t.add_default_plugins)) | ||||||
|         alertMask = (lt.alert.category_t.error_notification | |         alertMask = (gt.alert.category_t.error_notification | | ||||||
|                      lt.alert.category_t.storage_notification | |                      gt.alert.category_t.storage_notification | | ||||||
|                      lt.alert.category_t.tracker_notification | |                      gt.alert.category_t.tracker_notification | | ||||||
|                      lt.alert.category_t.status_notification) |                      gt.alert.category_t.status_notification) | ||||||
|         if self.config.debugAlerts: |         if self.config.debugAlerts: | ||||||
|             alertMask |= lt.alert.category_t.debug_notification |             alertMask |= gt.alert.category_t.debug_notification | ||||||
|         self.session.set_alert_mask(alertMask) |         self.session.set_alert_mask(alertMask) | ||||||
| 
 | 
 | ||||||
|         settings = self.session.get_settings() |         settings = self.session.get_settings() | ||||||
| @ -730,12 +739,12 @@ class Pyrrent2http(object): | |||||||
|         settings["tracker_backoff"] = 0 |         settings["tracker_backoff"] = 0 | ||||||
|         ### Непонятно, как заставить использовать прокси только для подключения к трекеру? |         ### Непонятно, как заставить использовать прокси только для подключения к трекеру? | ||||||
|         if self.config.proxy is not None: |         if self.config.proxy is not None: | ||||||
|             ps = lt.proxy_settings() |             ps = gt.proxy_settings() | ||||||
|             # peer_ps = lt.proxy_settings() |             # peer_ps = lt.proxy_settings() | ||||||
|             # peer_ps.type = lt.proxy_type.none |             # peer_ps.type = lt.proxy_type.none | ||||||
|             ps.hostname = self.config.proxy['host'] |             ps.hostname = self.config.proxy['host'] | ||||||
|             ps.port = self.config.proxy['port'] |             ps.port = self.config.proxy['port'] | ||||||
|             ps.type = lt.proxy_type.socks5 |             ps.type = gt.proxy_type.socks5 | ||||||
|             # self.session.set_peer_proxy(peer_ps) |             # self.session.set_peer_proxy(peer_ps) | ||||||
|             self.session.set_proxy(ps) |             self.session.set_proxy(ps) | ||||||
|             settings['force_proxy'] = False |             settings['force_proxy'] = False | ||||||
| @ -753,7 +762,7 @@ class Pyrrent2http(object): | |||||||
|                 strerror = e.args |                 strerror = e.args | ||||||
|                 logging.error(strerror) |                 logging.error(strerror) | ||||||
|             else: |             else: | ||||||
|                 self.session.load_state(lt.bdecode(bytes__)) |                 self.session.load_state(gt.bdecode(bytes__)) | ||||||
| 
 | 
 | ||||||
|         rand = SystemRandom(time.time()) |         rand = SystemRandom(time.time()) | ||||||
|         portLower = self.config.listenPort |         portLower = self.config.listenPort | ||||||
| @ -799,10 +808,10 @@ class Pyrrent2http(object): | |||||||
|                     logging.info('Added DHT router: %s:%d' % (host, port)) |                     logging.info('Added DHT router: %s:%d' % (host, port)) | ||||||
|         logging.info('Setting encryption settings') |         logging.info('Setting encryption settings') | ||||||
|         try: |         try: | ||||||
|             encryptionSettings = lt.pe_settings() |             encryptionSettings = gt.pe_settings() | ||||||
|             encryptionSettings.out_enc_policy = lt.enc_policy(self.config.encryption) |             encryptionSettings.out_enc_policy = gt.enc_policy(self.config.encryption) | ||||||
|             encryptionSettings.in_enc_policy = lt.enc_policy(self.config.encryption) |             encryptionSettings.in_enc_policy = gt.enc_policy(self.config.encryption) | ||||||
|             encryptionSettings.allowed_enc_level = lt.enc_level.both |             encryptionSettings.allowed_enc_level = gt.enc_level.both | ||||||
|             encryptionSettings.prefer_rc4 = True |             encryptionSettings.prefer_rc4 = True | ||||||
|             self.session.set_pe_settings(encryptionSettings) |             self.session.set_pe_settings(encryptionSettings) | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
| @ -871,7 +880,7 @@ class Pyrrent2http(object): | |||||||
|     def consumeAlerts(self): |     def consumeAlerts(self): | ||||||
|         alerts = self.session.pop_alerts() |         alerts = self.session.pop_alerts() | ||||||
|         for alert in alerts: |         for alert in alerts: | ||||||
|             if type(alert) == lt.save_resume_data_alert: |             if type(alert) == gt.save_resume_data_alert: | ||||||
|                 self.processSaveResumeDataAlert(alert) |                 self.processSaveResumeDataAlert(alert) | ||||||
|                 break |                 break | ||||||
| 
 | 
 | ||||||
| @ -907,7 +916,7 @@ class Pyrrent2http(object): | |||||||
| 
 | 
 | ||||||
|     def processSaveResumeDataAlert(self, alert): |     def processSaveResumeDataAlert(self, alert): | ||||||
|         logging.info('Saving resume data to: %s' % (encode_msg(self.config.resumeFile),)) |         logging.info('Saving resume data to: %s' % (encode_msg(self.config.resumeFile),)) | ||||||
|         data = lt.bencode(alert.resume_data) |         data = gt.bencode(alert.resume_data) | ||||||
|         try: |         try: | ||||||
|             with open(self.config.resumeFile, 'wb') as f: |             with open(self.config.resumeFile, 'wb') as f: | ||||||
|                 f.write(data) |                 f.write(data) | ||||||
| @ -918,9 +927,9 @@ class Pyrrent2http(object): | |||||||
|     def saveResumeData(self, async_=False): |     def saveResumeData(self, async_=False): | ||||||
|         if not self.torrentHandle.status().need_save_resume or self.config.resumeFile == '': |         if not self.torrentHandle.status().need_save_resume or self.config.resumeFile == '': | ||||||
|             return False |             return False | ||||||
|         self.torrentHandle.save_resume_data(lt.save_resume_flags_t.flush_disk_cache) |         self.torrentHandle.save_resume_data(gt.save_resume_flags_t.flush_disk_cache) | ||||||
|         if not async_: |         if not async_: | ||||||
|             alert = self.waitForAlert(lt.save_resume_data_alert, 5) |             alert = self.waitForAlert(gt.save_resume_data_alert, 5) | ||||||
|             if alert is None: |             if alert is None: | ||||||
|                 return False |                 return False | ||||||
|             self.processSaveResumeDataAlert(alert) |             self.processSaveResumeDataAlert(alert) | ||||||
| @ -930,7 +939,7 @@ class Pyrrent2http(object): | |||||||
|         if self.config.stateFile == '': |         if self.config.stateFile == '': | ||||||
|             return |             return | ||||||
|         entry = self.session.save_state() |         entry = self.session.save_state() | ||||||
|         data = lt.bencode(entry) |         data = gt.bencode(entry) | ||||||
|         logging.info('Saving session state to: %s' % (encode_msg(self.config.stateFile),)) |         logging.info('Saving session state to: %s' % (encode_msg(self.config.stateFile),)) | ||||||
|         try: |         try: | ||||||
|             logging.info('Saving session state to: %s' % (encode_msg(self.config.stateFile),)) |             logging.info('Saving session state to: %s' % (encode_msg(self.config.stateFile),)) | ||||||
| @ -973,14 +982,14 @@ class Pyrrent2http(object): | |||||||
|         state = self.torrentHandle.status().state |         state = self.torrentHandle.status().state | ||||||
|         if state != state.checking_files and not self.config.keepFiles: |         if state != state.checking_files and not self.config.keepFiles: | ||||||
|             if not self.config.keepComplete and not self.config.keepIncomplete: |             if not self.config.keepComplete and not self.config.keepIncomplete: | ||||||
|                 flag = int(lt.options_t.delete_files) |                 flag = int(gt.options_t.delete_files) | ||||||
|             else: |             else: | ||||||
|                 files = self.filesToRemove() |                 files = self.filesToRemove() | ||||||
|         logging.info('Removing the torrent') |         logging.info('Removing the torrent') | ||||||
|         self.session.remove_torrent(self.torrentHandle, flag) |         self.session.remove_torrent(self.torrentHandle, flag) | ||||||
|         if flag > 0 or len(files) > 0: |         if flag > 0 or len(files) > 0: | ||||||
|             logging.info('Waiting for files to be removed') |             logging.info('Waiting for files to be removed') | ||||||
|             self.waitForAlert(lt.torrent_deleted_alert, 15) |             self.waitForAlert(gt.torrent_deleted_alert, 15) | ||||||
|             self.removeFiles(files) |             self.removeFiles(files) | ||||||
| 
 | 
 | ||||||
|     def shutdown(self): |     def shutdown(self): | ||||||
| @ -992,7 +1001,7 @@ class Pyrrent2http(object): | |||||||
|         self.TorrentFS.Shutdown() |         self.TorrentFS.Shutdown() | ||||||
|         if self.session != None: |         if self.session != None: | ||||||
|             self.session.pause() |             self.session.pause() | ||||||
|             self.waitForAlert(lt.torrent_paused_alert, 10) |             self.waitForAlert(gt.torrent_paused_alert, 10) | ||||||
|             if self.torrentHandle is not None: |             if self.torrentHandle is not None: | ||||||
|                 self.saveResumeData(False) |                 self.saveResumeData(False) | ||||||
|                 self.saveSessionState() |                 self.saveSessionState() | ||||||
							
								
								
									
										11
									
								
								lib/gorrent2http/log.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/gorrent2http/log.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | import xbmc | ||||||
|  | from typing import Union | ||||||
|  | import chardet | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def info(msg : Union[str, bytes]): | ||||||
|  |     xbmc.log(f'INFO: {isinstance(msg, bytes) and msg.decode(chardet.detect(msg)["encoding"]) or msg}') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def error(msg: Union[str, bytes]): | ||||||
|  |     xbmc.log(f'ERROR: {isinstance(msg, bytes) and msg.decode(chardet.detect(msg)["encoding"]) or msg}') | ||||||
| @ -24,16 +24,17 @@ class Struct(dict): | |||||||
|         self[attr] = value |         self[attr] = value | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def uri2path(uri): | def uri2path(uri: str) -> str: | ||||||
|  |     uri_path: str = '' | ||||||
|     if uri[1] == ':' and sys.platform.startswith('win'): |     if uri[1] == ':' and sys.platform.startswith('win'): | ||||||
|         uri = 'file:///' + uri |         uri = 'file:///' + uri | ||||||
|     fileUri = urllib.parse.urlparse(uri) |     file_uri = urllib.parse.urlparse(uri) | ||||||
|     if fileUri.scheme == 'file': |     if file_uri.scheme == 'file': | ||||||
|         uriPath = fileUri.path |         uri_path = file_uri.path | ||||||
|         if uriPath != '' and sys.platform.startswith('win') and (os.path.sep == uriPath[0] or uriPath[0] == '/'): |         if uri_path != '' and sys.platform.startswith('win') and (os.path.sep == uri_path[0] or uri_path[0] == '/'): | ||||||
|             uriPath = uriPath[1:] |             uri_path = uri_path[1:] | ||||||
|     absPath = os.path.abspath(urllib.parse.unquote(uriPath)) |     abs_path = os.path.abspath(urllib.parse.unquote(uri_path)) | ||||||
|     return localize_path(absPath) |     return localize_path(abs_path) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def detect_media_type(name): | def detect_media_type(name): | ||||||
| @ -114,3 +115,62 @@ def ensure_fs_encoding(string): | |||||||
|     if isinstance(string, bytes): |     if isinstance(string, bytes): | ||||||
|         string = string.decode('utf-8') |         string = string.decode('utf-8') | ||||||
|     return string.encode(sys.getfilesystemencoding() or 'utf-8') |     return string.encode(sys.getfilesystemencoding() or 'utf-8') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_platform(): | ||||||
|  |         ret = { | ||||||
|  |             "arch": sys.maxsize > 2 ** 32 and "x64" or "x86", | ||||||
|  |         } | ||||||
|  |         if xbmc.getCondVisibility("system.platform.android"): | ||||||
|  |             ret["os"] = "android" | ||||||
|  |             if "arm" in os.uname()[4] or "aarch64" in os.uname()[4]: | ||||||
|  |                 ret["arch"] = "arm" | ||||||
|  |         elif xbmc.getCondVisibility("system.platform.linux"): | ||||||
|  |             ret["os"] = "linux" | ||||||
|  |             uname = os.uname()[4] | ||||||
|  |             if "arm" in uname: | ||||||
|  |                 if "armv7" in uname: | ||||||
|  |                     ret["arch"] = "armv7" | ||||||
|  |                 else: | ||||||
|  |                     ret["arch"] = "armv6" | ||||||
|  |             elif "mips" in uname: | ||||||
|  |                 ret["arch"] = 'mipsel' | ||||||
|  |             elif "aarch64" in uname: | ||||||
|  |                 if sys.maxsize > 2147483647:  # is_64bit_system | ||||||
|  |                     ret["arch"] = 'aarch64' | ||||||
|  |                 else: | ||||||
|  |                     ret["arch"] = "armv7"  # 32-bit userspace | ||||||
|  |         elif xbmc.getCondVisibility("system.platform.windows"): | ||||||
|  |             ret["os"] = "windows" | ||||||
|  |         elif xbmc.getCondVisibility("system.platform.osx"): | ||||||
|  |             ret["os"] = "darwin" | ||||||
|  |         elif xbmc.getCondVisibility("system.platform.ios"): | ||||||
|  |             ret["os"] = "ios" | ||||||
|  |             ret["arch"] = "arm" | ||||||
|  | 
 | ||||||
|  |         ret = get_system(ret) | ||||||
|  |         return ret | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_system(ret): | ||||||
|  |     ret["system"] = '' | ||||||
|  |     if ret["os"] == 'windows': | ||||||
|  |         ret["system"] = 'windows_' + ret['arch'] | ||||||
|  |     elif ret["os"] == "linux" and ret["arch"] == "x64": | ||||||
|  |         ret["system"] = 'linux_x86_64' | ||||||
|  |     elif ret["os"] == "linux" and ret["arch"] == "x86": | ||||||
|  |         ret["system"] = 'linux_x86' | ||||||
|  |     elif ret["os"] == "linux" and "aarch64" in ret["arch"]: | ||||||
|  |         ret["system"] = 'linux_' + ret["arch"] | ||||||
|  |     elif ret["os"] == "linux" and ("arm" in ret["arch"] or 'mips' in ret["arch"]): | ||||||
|  |         ret["system"] = 'linux_' + ret["arch"] | ||||||
|  |     elif ret["os"] == "android": | ||||||
|  |         if ret["arch"] == 'arm': | ||||||
|  |             ret["system"] = 'android_armv7' | ||||||
|  |         else: | ||||||
|  |             ret["system"] = 'android_x86' | ||||||
|  |     elif ret["os"] == "darwin": | ||||||
|  |         ret["system"] = 'darwin' | ||||||
|  |     elif ret["os"] == "ios" and ret["arch"] == "arm": | ||||||
|  |         ret["system"] = 'ios_arm' | ||||||
|  |     return ret | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user