diff --git a/Anteoloader.py b/Anteoloader.py
index 35700ca..999c3c2 100644
--- a/Anteoloader.py
+++ b/Anteoloader.py
@@ -1,701 +1,701 @@
-# -*- coding: utf-8 -*-
-'''
- Torrenter v2 plugin for XBMC/Kodi
- Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-'''
-
-
-import urllib2
-import hashlib
-import re
-from StringIO import StringIO
-import gzip
-
-import xbmc
-import xbmcgui
-import xbmcvfs
-import Localization
-from functions import file_encode, isSubtitle, DownloadDB, log, debug, is_writable, unquote, file_url
-
-
-import os
-import urllib
-import sys
-from contextlib import contextmanager, closing, nested
-
-
-from functions import foldername, showMessage, clearStorage, WatchedHistoryDB, get_ids_video, log, debug, ensure_str
-
-if sys.modules["__main__"].__settings__.getSetting("torrent_player") == '2':
- from torrent2http import State, Engine, MediaType
- author = 'Anteo'
-elif sys.modules["__main__"].__settings__.getSetting("torrent_player") == '3':
- from pyrrent2http import State, Engine, MediaType
- author = 'Inpos'
-
-ROOT = sys.modules["__main__"].__root__
-RESOURCES_PATH = os.path.join(ROOT, 'resources')
-TORRENT2HTTP_TIMEOUT = 20
-TORRENT2HTTP_POLL = 1000
-PLAYING_EVENT_INTERVAL = 60
-MIN_COMPLETED_PIECES = 0.5
-
-WINDOW_FULLSCREEN_VIDEO = 12005
-
-XBFONT_LEFT = 0x00000000
-XBFONT_RIGHT = 0x00000001
-XBFONT_CENTER_X = 0x00000002
-XBFONT_CENTER_Y = 0x00000004
-XBFONT_TRUNCATED = 0x00000008
-XBFONT_JUSTIFY = 0x00000010
-
-STATE_STRS = [
- 'Queued',
- 'Checking',
- 'Downloading metadata',
- 'Downloading',
- 'Finished',
- 'Seeding',
- 'Allocating',
- 'Allocating file & Checking resume'
-]
-
-VIEWPORT_WIDTH = 1920.0
-VIEWPORT_HEIGHT = 1088.0
-OVERLAY_WIDTH = int(VIEWPORT_WIDTH * 0.7) # 70% size
-OVERLAY_HEIGHT = 150
-
-ENCRYPTION_SETTINGS = {
- "Forced": 0,
- "Enabled": 1,
- "Disabled": 2,
-}
-
-class Encryption:
- FORCED = 0
- ENABLED = 1
- DISABLED = 2
-
-class AnteoLoader:
- magnetLink = None
- engine = None
- torrentFile = None
- __plugin__ = sys.modules["__main__"].__plugin__
- __settings__ = sys.modules["__main__"].__settings__
-
- def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
- self.storageDirectory = storageDirectory
- self.torrentFilesPath = os.path.join(self.storageDirectory, torrentFilesDirectory) + os.sep
- if not is_writable(self.storageDirectory):
- xbmcgui.Dialog().ok(self.localize('Torrenter v2'),
- self.localize('Your storage path is not writable or not local! Please change it in settings!'),
- self.localize(self.storageDirectory))
-
- sys.exit(1)
-
- #pre settings
- if re.match("^magnet\:.+$", torrentFile):
- self.magnetLink = torrentFile
- else:
- self.torrentFile = torrentFile
-
- def __exit__(self):
- log('on __exit__')
- if self.engine:
- self.engine.close()
- log('__exit__ worked!')
-
- def setup_engine(self):
- encryption = Encryption.ENABLED if self.__settings__.getSetting('encryption') == 'true' else Encryption.DISABLED
-
- if self.__settings__.getSetting("connections_limit") not in ["",0,"0"]:
- connections_limit = int(self.__settings__.getSetting("connections_limit"))
- else:
- connections_limit = None
-
- use_random_port = True if self.__settings__.getSetting('use_random_port') == 'true' else False
-
- listen_port=int(self.__settings__.getSetting("listen_port")) if self.__settings__.getSetting(
- "listen_port") != "" else 6881
-
- if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.storageDirectory:
- keep_complete = False
- keep_incomplete = False
- else:
- keep_complete = True
- keep_incomplete = True
-
- dht_routers = ["router.bittorrent.com:6881", "router.utorrent.com:6881"]
- user_agent = 'uTorrent/2200(24683)'
- self.engine = Engine(uri=file_url(self.torrentFile), download_path=self.storageDirectory,
- connections_limit=connections_limit,
- encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
- dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
- user_agent=user_agent)
-
- def localize(self, string):
- try:
- return Localization.localize(string)
- except:
- return string
-
- def getContentList(self):
- self.setup_engine()
- files = []
- filelist = []
- with closing(self.engine):
- self.engine.start()
- #media_types=[MediaType.VIDEO, MediaType.AUDIO, MediaType.SUBTITLES, MediaType.UNKNOWN]
-
- iterator = 0
- text = Localization.localize('Magnet-link is converting') if self.magnetLink\
- else Localization.localize('Opening torrent file')
- while not files and not xbmc.abortRequested and iterator < 100:
- files = self.engine.list()
- self.engine.check_torrent_error()
- if iterator==4:
- progressBar = xbmcgui.DialogProgress()
- progressBar.create(Localization.localize('Please Wait'),
- Localization.localize('Magnet-link is converting'))
- elif iterator>4:
- progressBar.update(iterator, Localization.localize('Please Wait'),text+'.' * (iterator % 4), ' ')
- if progressBar.iscanceled():
- progressBar.update(0)
- progressBar.close()
- return []
- xbmc.sleep(500)
- iterator += 1
-
- for fs in files:
- stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
- 'offset': fs.offset}
- filelist.append(stringdata)
- return filelist
-
- def saveTorrent(self, torrentUrl):
- #if not xbmcvfs.exists(torrentUrl) or re.match("^http.+$", torrentUrl):
- if re.match("^magnet\:.+$", torrentUrl):
- self.magnetLink = torrentUrl
- self.magnetToTorrent(torrentUrl)
- self.magnetLink = None
- return self.torrentFile
- else:
- if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
- torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
- try:
- if not re.match("^http\:.+$", torrentUrl):
- content = xbmcvfs.File(torrentUrl, "rb").read()
- else:
- request = urllib2.Request(torrentUrl)
- request.add_header('Referer', torrentUrl)
- request.add_header('Accept-encoding', 'gzip')
- result = urllib2.urlopen(request)
- if result.info().get('Content-Encoding') == 'gzip':
- buf = StringIO(result.read())
- f = gzip.GzipFile(fileobj=buf)
- content = f.read()
- else:
- content = result.read()
-
- localFile = xbmcvfs.File(torrentFile, "w+b")
- localFile.write(content)
- localFile.close()
- except Exception, e:
- log('Unable to rename torrent file from %s to %s in AnteoLoader::saveTorrent. Exception: %s' %
- (torrentUrl, torrentFile, str(e)))
- return
- #else:
- #torrentFile = torrentUrl
- if xbmcvfs.exists(torrentFile) and not os.path.exists(torrentFile):
- if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
- torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
- xbmcvfs.copy(torrentUrl, torrentFile)
- if os.path.exists(torrentFile):
- self.torrentFile = torrentFile
- return self.torrentFile
-
- def md5(self, string):
- hasher = hashlib.md5()
- try:
- hasher.update(string)
- except:
- hasher.update(string.encode('utf-8', 'ignore'))
- return hasher.hexdigest()
-
- def magnetToTorrent(self, magnet):
- try:
- from Libtorrent import Libtorrent
- torrent = Libtorrent(self.storageDirectory, magnet)
- torrent.magnetToTorrent(magnet)
- self.torrentFile = torrent.torrentFile
- except:
- self.torrentFile = magnet
- log('['+author+'Loader][magnetToTorrent]: self.torrentFile '+str(self.torrentFile))
-
-class AnteoPlayer(xbmc.Player):
- __plugin__ = sys.modules["__main__"].__plugin__
- __settings__ = sys.modules["__main__"].__settings__
- ROOT = sys.modules["__main__"].__root__ # .decode('utf-8').encode(sys.getfilesystemencoding())
- USERAGENT = "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0"
- torrentFilesDirectory = 'torrents'
- debug = __settings__.getSetting('debug') == 'true'
- subs_dl = __settings__.getSetting('subs_dl') == 'true'
- seeding = __settings__.getSetting('keep_seeding') == 'true' and __settings__.getSetting('keep_files') == '1'
- seeding_status = False
- seeding_run = False
- ids_video = None
- episodeId = None
- fullSize = 0
- watchedTime = 0
- totalTime = 1
- seek = 0
- basename = ''
-
- def __init__(self, userStorageDirectory, torrentUrl, params={}):
- self.userStorageDirectory = userStorageDirectory
- self.torrentUrl = torrentUrl
- xbmc.Player.__init__(self)
- log("[AnteoPlayer] Initalized")
- self.params = params
- self.get = self.params.get
- self.contentId = int(self.get("url"))
- if self.get("seek"):
- self.seek = int(self.get("seek"))
- #self.torrent = AnteoLoader(self.userStorageDirectory, self.torrentUrl, self.torrentFilesDirectory)
- self.init()
- self.setup_engine()
- with closing(self.engine):
- self.engine.start(self.contentId)
- self.setup_nextep()
- while True:
- if self.buffer():
- log('['+author+'Player]: ************************************* GOING LOOP')
- if self.setup_play():
- self.setup_subs()
- self.loop()
- WatchedHistoryDB().add(self.basename, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
- else:
- log('['+author+'Player]: ************************************* break')
- break
- log('['+author+'Player]: ************************************* GO NEXT?')
- if self.next_dl and self.next_contentId != False and isinstance(self.next_contentId, int) and self.iterator == 100:
- if not self.next_play:
- xbmc.sleep(3000)
- if not xbmcgui.Dialog().yesno(
- self.localize('Torrent2HTTP'),
- self.localize('Would you like to play next episode?')):
- break
- self.contentId = self.next_contentId
- continue
- log('['+author+'Player]: ************************************* NO! break')
- break
-
- xbmc.Player().stop()
-
- if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.userStorageDirectory:
- xbmc.sleep(1000)
- clearStorage(self.userStorageDirectory)
- else:
- #if self.seeding_status:
- #showMessage(self.localize('Information'),
- # self.localize('Torrent is seeding. To stop it use Download Status.'), forced=True)
- #else:
- #if self.seeding: self.db_delete()
- showMessage(self.localize('Information'),
- self.localize('Torrent downloading is stopped.'), forced=True)
-
- def __exit__(self):
- log('on __exit__')
- if self.engine:
- self.engine.close()
- log('__exit__ worked!')
-
- def init(self):
- self.next_contentId = False
- self.display_name = ''
- self.downloadedSize = 0
- self.dialog = xbmcgui.Dialog()
- self.on_playback_started = []
- self.on_playback_resumed = []
- self.on_playback_paused = []
- self.on_playback_stopped = []
- self.torrentUrl = self.torrentUrl
-
- def setup_engine(self):
- #uri=None, binaries_path=None, platform=None, download_path=".",
- #bind_host='127.0.0.1', bind_port=5001, connections_limit=None, download_kbps=None, upload_kbps=None,
- #enable_dht=True, enable_lsd=True, enable_natpmp=True, enable_upnp=True, enable_scrape=False,
- #log_stats=False, encryption=Encryption.ENABLED, keep_complete=False, keep_incomplete=False,
- #keep_files=False, log_files_progress=False, log_overall_progress=False, log_pieces_progress=False,
- #listen_port=6881, use_random_port=False, max_idle_timeout=None, no_sparse=False, resume_file=None,
- #user_agent=None, startup_timeout=5, state_file=None, enable_utp=True, enable_tcp=True,
- #debug_alerts=False, logger=None, torrent_connect_boost=50, connection_speed=50,
- #peer_connect_timeout=15, request_timeout=20, min_reconnect_time=60, max_failcount=3,
- #dht_routers=None, trackers=None)
-
- encryption = Encryption.ENABLED if self.__settings__.getSetting('encryption') == 'true' else Encryption.DISABLED
- upload_limit = int(self.__settings__.getSetting("upload_limit"))*1024/8 if self.__settings__.getSetting(
- "upload_limit") != "" else 0
- download_limit = int(self.__settings__.getSetting("download_limit"))*1024/8 if self.__settings__.getSetting(
- "download_limit") != "" else 0
-
- if self.__settings__.getSetting("connections_limit") not in ["",0,"0"]:
- connections_limit = int(self.__settings__.getSetting("connections_limit"))
- else:
- connections_limit = None
-
- use_random_port = True if self.__settings__.getSetting('use_random_port') == 'true' else False
-
- listen_port=int(self.__settings__.getSetting("listen_port")) if self.__settings__.getSetting(
- "listen_port") != "" else 6881
-
- if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.userStorageDirectory:
- keep_complete = False
- keep_incomplete = False
- keep_files = False
- resume_file = None
- else:
- keep_complete = True
- keep_incomplete = True
- keep_files = True
- resume_file=os.path.join(self.userStorageDirectory, 'torrents', os.path.basename(self.torrentUrl)+'.resume_data')
-
- dht_routers = ["router.bittorrent.com:6881","router.utorrent.com:6881"]
- user_agent = 'uTorrent/2200(24683)'
- self.pre_buffer_bytes = int(self.__settings__.getSetting("pre_buffer_bytes"))*1024*1024
-
- self.engine = Engine(uri=file_url(self.torrentUrl), download_path=self.userStorageDirectory,
- connections_limit=connections_limit, download_kbps=download_limit, upload_kbps=upload_limit,
- encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
- dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
- keep_files=keep_files, user_agent=user_agent, resume_file=resume_file)
-
- def buffer(self):
- #self.pre_buffer_bytes = 30*1024*1024 #30 MB
- ready = False
- progressBar = xbmcgui.DialogProgress()
- progressBar.create(self.localize('Please Wait'),
- self.localize('Seeds searching.'))
- #if self.subs_dl:
- # subs = self.torrent.getSubsIds(os.path.basename(self.torrent.getFilePath(self.contentId)))
- # if len(subs) > 0:
- # for ind, title in subs:
- # self.torrent.continueSession(ind)
-
- while not xbmc.abortRequested and not ready:
- xbmc.sleep(500)
- status = self.engine.status()
- self.print_debug(status)
- #self.print_fulldebug()
- self.engine.check_torrent_error(status)
- file_status = self.engine.file_status(self.contentId)
- if not file_status:
- continue
- self.fullSize = int(file_status.size / 1024 / 1024)
- downloadedSize = status.total_download / 1024 / 1024
- getDownloadRate = status.download_rate / 1024 * 8
- getUploadRate = status.upload_rate / 1024 * 8
- getSeeds, getPeers = status.num_seeds, status.num_peers
- iterator = int(round(float(file_status.download) / self.pre_buffer_bytes, 2) * 100)
- if iterator > 99: iterator = 99
- if status.state == State.CHECKING_FILES:
- iterator = int(status.progress*100)
- if iterator > 99: iterator = 99
- progressBar.update(iterator, self.localize('Checking preloaded files...'), ' ', ' ')
- elif status.state == State.DOWNLOADING:
- dialogText = self.localize('Preloaded: ') + "%d MB / %d MB" % \
- (int(downloadedSize), self.fullSize)
- peersText = ' [%s: %s; %s: %s]' % (
- self.localize('Seeds'), getSeeds, self.localize('Peers'), getPeers)
- speedsText = '%s: %d Mbit/s; %s: %d Mbit/s' % (
- self.localize('Downloading'), int(getDownloadRate),
- self.localize('Uploading'), int(getUploadRate))
- progressBar.update(iterator, self.localize('Seeds searching.') + peersText, dialogText,
- speedsText)
-
- if file_status.download >= self.pre_buffer_bytes:
- ready = True
- break
- elif status.state in [State.FINISHED, State.SEEDING]:
- ready = True
- break
- else:
- progressBar.update(iterator, self.localize('UNKNOWN STATUS'), ' ', ' ')
- if progressBar.iscanceled():
- self.iterator = 0
- ready = False
- break
-
- progressBar.update(0)
- progressBar.close()
- return ready
-
- def setup_nextep(self):
- try:
- if self.get("url2"):
- debug("[setup_nextep]: url2")
- self.ids_video = urllib.unquote_plus(self.get("url2")).split(',')
- else:
- debug("[setup_nextep]: not url2")
- self.ids_video = self.get_ids()
- except:
- pass
-
- if self.__settings__.getSetting('next_dl') == 'true' and self.ids_video and len(self.ids_video)>1:
- self.next_dl = True
- else:
- self.next_dl = False
- self.next_play = self.__settings__.getSetting('next_play') == 'true'
- log('['+author+'Player]: next_dl - %s, next_play - %s, ids_video - %s' % (str(self.next_dl), str(self.next_play), str(self.ids_video)))
-
- def setup_play(self):
- file_status = self.engine.file_status(self.contentId)
- self.iterator = 0
- self.watchedTime = 0
- self.totalTime = 1
- url = file_status.url
- label = os.path.basename(file_status.name)
- self.basename = label
- self.seeding_run = False
- listitem = xbmcgui.ListItem(label, path=url)
-
- if self.next_dl:
- next_contentId_index = self.ids_video.index(str(self.contentId)) + 1
- if len(self.ids_video) > next_contentId_index:
- self.next_contentId = int(self.ids_video[next_contentId_index])
- else:
- self.next_contentId = False
- log('['+author+'Player][setup_play]: next_contentId: '+str(self.next_contentId))
- try:
- seasonId = self.get("seasonId")
- self.episodeId = self.get("episodeId") if not self.episodeId else int(self.episodeId) + 1
- title = urllib.unquote_plus(self.get("title")) if self.get("title") else None
-
- if self.get("label") and self.episodeId == self.get("episodeId"):
- label = urllib.unquote_plus(self.get("label"))
- elif seasonId and self.episodeId and title:
- label = '%s S%02dE%02d.%s (%s)' % (
- title, int(seasonId), int(self.episodeId), self.basename.split('.')[-1], self.basename)
-
- if seasonId and self.episodeId and label and title:
- listitem = xbmcgui.ListItem(label, path=url)
-
- listitem.setInfo(type='video', infoLabels={'title': label,
- 'episode': int(self.episodeId),
- 'season': int(seasonId),
- 'tvshowtitle': title})
- except:
- log('['+author+'Player]: Operation INFO failed!')
-
- thumbnail = self.get("thumbnail")
- if thumbnail:
- listitem.setThumbnailImage(urllib.unquote_plus(thumbnail))
- self.display_name = label
-
- player = xbmc.Player()
- player.play(url, listitem)
-
- xbmc.sleep(2000) # very important, do not edit this, podavan
- i = 0
- while not xbmc.abortRequested and not self.isPlaying() and i < 50:
- xbmc.sleep(200)
- i += 1
-
- log('['+author+'Player]: self.isPlaying() = %s, i = %d, xbmc.abortRequested - %s' % (str(self.isPlaying()), i, str(xbmc.abortRequested)))
- if not self.isPlaying() or xbmc.abortRequested:
- return False
-
- if self.seek > 0:
- log('['+author+'Player]: seekTime - '+str(self.seek))
- self.seekTime(self.seek)
- return True
-
- def setup_subs(self):
- if self.subs_dl:
- file_status = self.engine.file_status(self.contentId)
- subs = []
- filename = os.path.basename(file_status.name)
- sub_files = self.engine.list(media_types=[MediaType.SUBTITLES])
- for i in sub_files:
- if isSubtitle(filename, i.name):
- subs.append(i)
- if subs:
- log("[AnteoPlayer][setup_subs]: Detected subtitles: %s" % str(subs))
- for sub in subs:
- xbmc.Player().setSubtitles(sub.url)
-
- def loop(self):
- debug_counter = 0
- pause = True
- with closing(
- OverlayText(w=OVERLAY_WIDTH, h=OVERLAY_HEIGHT, alignment=XBFONT_CENTER_X | XBFONT_CENTER_Y)) as overlay:
- with nested(self.attach(overlay.show, self.on_playback_paused),
- self.attach(overlay.hide, self.on_playback_resumed, self.on_playback_stopped)):
- while not xbmc.abortRequested and self.isPlaying():
- #self.print_fulldebug()
- status = self.engine.status()
- file_status = self.engine.file_status(self.contentId)
- self.watchedTime = xbmc.Player().getTime()
- self.totalTime = xbmc.Player().getTotalTime()
- if self.iterator == 100 and debug_counter < 100:
- debug_counter += 1
- else:
- self.print_debug(status)
- debug_counter=0
-
- overlay.text = "\n".join(self._get_status_lines(status, file_status))
-
- self.iterator = int(file_status.progress * 100)
-
- if pause and self.__settings__.getSetting("pause_onplay") == 'true':
- pause = False
- xbmc.Player().pause()
- xbmc.sleep(1000)
-
- #if not self.seeding_run and self.iterator == 100 and self.seeding:
- #self.seeding_run = True
- #self.seed(self.contentId)
- #self.seeding_status = True
- # xbmc.sleep(7000)
-
- def onPlayBackStarted(self):
- for f in self.on_playback_started:
- f()
- log('[onPlayBackStarted]: '+(str(("video", "play", self.display_name))))
-
- def onPlayBackResumed(self):
- for f in self.on_playback_resumed:
- f()
- self.onPlayBackStarted()
-
- def onPlayBackPaused(self):
- for f in self.on_playback_paused:
- f()
- log('[onPlayBackPaused]: '+(str(("video", "pause", self.display_name))))
-
- def onPlayBackStopped(self):
- for f in self.on_playback_stopped:
- f()
- log('[onPlayBackStopped]: '+(str(("video", "stop", self.display_name))))
-
- @contextmanager
- def attach(self, callback, *events):
- for event in events:
- event.append(callback)
- yield
- for event in events:
- event.remove(callback)
-
- def _get_status_lines(self, s, f):
- return [
- self.display_name,
- "%.2f%% %s" % (f.progress * 100, self.localize(STATE_STRS[s.state]).decode('utf-8')),
- "D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate, self.localize('kb/s').decode('utf-8'),
- s.upload_rate, self.localize('kb/s').decode('utf-8'),
- s.num_seeds, s.num_peers)
- ]
-
- def localize(self, string):
- try:
- return Localization.localize(string)
- except:
- return string
-
- def print_debug(self, status=None):
- #FileStatus = namedtuple('FileStatus', "name, save_path, url, size, offset, download, progress, index, media_type")
-
- #SessionStatus = namedtuple('SessionStatus', "name, state, state_str, error, progress, download_rate, upload_rate, "
- # "total_download, total_upload, num_peers, num_seeds, total_seeds, "
- # "total_peers")
-
- #log('[buffer] file_status:'+str(file_status))
- #log('[buffer] status:'+str(status))
- if not status:
- status = self.engine.status()
- self.engine.check_torrent_error(status)
- log('['+author+'Player]: %.2f%% complete (down: %.1f kb/s up: %.1f kb/s peers: %d) %s' % \
- (status.progress * 100, status.download_rate,
- status.upload_rate, status.num_peers, status.state_str))
-
- def print_fulldebug(self):
- status = self.engine.status()
- file_status = self.engine.file_status(self.contentId)
- log('[buffer] file_status:'+str(file_status))
- log('[buffer] status:'+str(status))
-
- def get_ids(self):
- contentList = []
- for fs in self.engine.list():
- contentList.append((fs.name, str(fs.index)))
- contentList = sorted(contentList, key=lambda x: x[0])
- return get_ids_video(contentList)
-
- def getContentList(self):
- filelist = []
- for fs in self.engine.list():
- stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
- 'offset': fs.offset}
- filelist.append(stringdata)
- return filelist
-
-class OverlayText(object):
- def __init__(self, w, h, *args, **kwargs):
- self.window = xbmcgui.Window(WINDOW_FULLSCREEN_VIDEO)
- viewport_w, viewport_h = self._get_skin_resolution()
- # Adjust size based on viewport, we are using 1080p coordinates
- w = int(w * viewport_w / VIEWPORT_WIDTH)
- h = int(h * viewport_h / VIEWPORT_HEIGHT)
- x = (viewport_w - w) / 2
- y = (viewport_h - h) / 2
- self._shown = False
- self._text = ""
- self._label = xbmcgui.ControlLabel(x, y, w, h, self._text, *args, **kwargs)
- self._background = xbmcgui.ControlImage(x, y, w, h, os.path.join(RESOURCES_PATH, "images", "black.png"))
- self._background.setColorDiffuse("0xD0000000")
-
- def show(self):
- if not self._shown:
- self.window.addControls([self._background, self._label])
- self._shown = True
- self._background.setColorDiffuse("0xD0000000")
-
- def hide(self):
- if self._shown:
- self._shown = False
- self.window.removeControls([self._background, self._label])
- self._background.setColorDiffuse("0xFF000000")
-
- def close(self):
- self.hide()
-
- @property
- def text(self):
- return self._text
-
- @text.setter
- def text(self, text):
- self._text = text
- if self._shown:
- self._label.setLabel(self._text)
-
- # This is so hackish it hurts.
- def _get_skin_resolution(self):
- import xml.etree.ElementTree as ET
-
- skin_path = xbmc.translatePath("special://skin/")
- tree = ET.parse(os.path.join(skin_path, "addon.xml"))
- res = tree.findall("./extension/res")[0]
+# -*- coding: utf-8 -*-
+'''
+ Torrenter v2 plugin for XBMC/Kodi
+ Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+'''
+
+
+import urllib2
+import hashlib
+import re
+from StringIO import StringIO
+import zlib
+
+import xbmc
+import xbmcgui
+import xbmcvfs
+import Localization
+from functions import file_encode, isSubtitle, DownloadDB, log, debug, is_writable, unquote, file_url
+
+
+import os
+import urllib
+import sys
+from contextlib import contextmanager, closing, nested
+
+
+from functions import foldername, showMessage, clearStorage, WatchedHistoryDB, get_ids_video, log, debug, ensure_str
+
+if sys.modules["__main__"].__settings__.getSetting("torrent_player") == '2':
+ from torrent2http import State, Engine, MediaType
+ author = 'Anteo'
+elif sys.modules["__main__"].__settings__.getSetting("torrent_player") == '3':
+ from pyrrent2http import State, Engine, MediaType
+ author = 'Inpos'
+
+ROOT = sys.modules["__main__"].__root__
+RESOURCES_PATH = os.path.join(ROOT, 'resources')
+TORRENT2HTTP_TIMEOUT = 20
+TORRENT2HTTP_POLL = 1000
+PLAYING_EVENT_INTERVAL = 60
+MIN_COMPLETED_PIECES = 0.5
+
+WINDOW_FULLSCREEN_VIDEO = 12005
+
+XBFONT_LEFT = 0x00000000
+XBFONT_RIGHT = 0x00000001
+XBFONT_CENTER_X = 0x00000002
+XBFONT_CENTER_Y = 0x00000004
+XBFONT_TRUNCATED = 0x00000008
+XBFONT_JUSTIFY = 0x00000010
+
+STATE_STRS = [
+ 'Queued',
+ 'Checking',
+ 'Downloading metadata',
+ 'Downloading',
+ 'Finished',
+ 'Seeding',
+ 'Allocating',
+ 'Allocating file & Checking resume'
+]
+
+VIEWPORT_WIDTH = 1920.0
+VIEWPORT_HEIGHT = 1088.0
+OVERLAY_WIDTH = int(VIEWPORT_WIDTH * 0.7) # 70% size
+OVERLAY_HEIGHT = 150
+
+ENCRYPTION_SETTINGS = {
+ "Forced": 0,
+ "Enabled": 1,
+ "Disabled": 2,
+}
+
+class Encryption:
+ FORCED = 0
+ ENABLED = 1
+ DISABLED = 2
+
+class AnteoLoader:
+ magnetLink = None
+ engine = None
+ torrentFile = None
+ __plugin__ = sys.modules["__main__"].__plugin__
+ __settings__ = sys.modules["__main__"].__settings__
+
+ def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
+ self.storageDirectory = storageDirectory
+ self.torrentFilesPath = os.path.join(self.storageDirectory, torrentFilesDirectory) + os.sep
+ if not is_writable(self.storageDirectory):
+ xbmcgui.Dialog().ok(self.localize('Torrenter v2'),
+ self.localize('Your storage path is not writable or not local! Please change it in settings!'),
+ self.localize(self.storageDirectory))
+
+ sys.exit(1)
+
+ #pre settings
+ if re.match("^magnet\:.+$", torrentFile):
+ self.magnetLink = torrentFile
+ else:
+ self.torrentFile = torrentFile
+
+ def __exit__(self):
+ log('on __exit__')
+ if self.engine:
+ self.engine.close()
+ log('__exit__ worked!')
+
+ def setup_engine(self):
+ encryption = Encryption.ENABLED if self.__settings__.getSetting('encryption') == 'true' else Encryption.DISABLED
+
+ if self.__settings__.getSetting("connections_limit") not in ["",0,"0"]:
+ connections_limit = int(self.__settings__.getSetting("connections_limit"))
+ else:
+ connections_limit = None
+
+ use_random_port = True if self.__settings__.getSetting('use_random_port') == 'true' else False
+
+ listen_port=int(self.__settings__.getSetting("listen_port")) if self.__settings__.getSetting(
+ "listen_port") != "" else 6881
+
+ if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.storageDirectory:
+ keep_complete = False
+ keep_incomplete = False
+ else:
+ keep_complete = True
+ keep_incomplete = True
+
+ dht_routers = ["router.bittorrent.com:6881", "router.utorrent.com:6881"]
+ user_agent = 'uTorrent/2200(24683)'
+ self.engine = Engine(uri=file_url(self.torrentFile), download_path=self.storageDirectory,
+ connections_limit=connections_limit,
+ encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
+ dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
+ user_agent=user_agent)
+
+ def localize(self, string):
+ try:
+ return Localization.localize(string)
+ except:
+ return string
+
+ def getContentList(self):
+ self.setup_engine()
+ files = []
+ filelist = []
+ with closing(self.engine):
+ self.engine.start()
+ #media_types=[MediaType.VIDEO, MediaType.AUDIO, MediaType.SUBTITLES, MediaType.UNKNOWN]
+
+ iterator = 0
+ text = Localization.localize('Magnet-link is converting') if self.magnetLink\
+ else Localization.localize('Opening torrent file')
+ while not files and not xbmc.abortRequested and iterator < 100:
+ files = self.engine.list()
+ self.engine.check_torrent_error()
+ if iterator==4:
+ progressBar = xbmcgui.DialogProgress()
+ progressBar.create(Localization.localize('Please Wait'),
+ Localization.localize('Magnet-link is converting'))
+ elif iterator>4:
+ progressBar.update(iterator, Localization.localize('Please Wait'),text+'.' * (iterator % 4), ' ')
+ if progressBar.iscanceled():
+ progressBar.update(0)
+ progressBar.close()
+ return []
+ xbmc.sleep(500)
+ iterator += 1
+
+ for fs in files:
+ stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
+ 'offset': fs.offset}
+ filelist.append(stringdata)
+ return filelist
+
+ def saveTorrent(self, torrentUrl):
+ #if not xbmcvfs.exists(torrentUrl) or re.match("^http.+$", torrentUrl):
+ if re.match("^magnet\:.+$", torrentUrl):
+ self.magnetLink = torrentUrl
+ self.magnetToTorrent(torrentUrl)
+ self.magnetLink = None
+ return self.torrentFile
+ else:
+ if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
+ torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
+ try:
+ if not re.match("^http\:.+$", torrentUrl):
+ content = xbmcvfs.File(torrentUrl, "rb").read()
+ else:
+ request = urllib2.Request(torrentUrl)
+ request.add_header('Referer', torrentUrl)
+ request.add_header('Accept-encoding', 'gzip')
+ result = urllib2.urlopen(request)
+ if result.info().get('Content-Encoding') == 'gzip':
+ buf = StringIO(result.read())
+ decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
+ content = decomp.decompress(buf.getvalue())
+ else:
+ content = result.read()
+
+ localFile = xbmcvfs.File(torrentFile, "w+b")
+ localFile.write(content)
+ localFile.close()
+ except Exception, e:
+ log('Unable to rename torrent file from %s to %s in AnteoLoader::saveTorrent. Exception: %s' %
+ (torrentUrl, torrentFile, str(e)))
+ return
+ #else:
+ #torrentFile = torrentUrl
+ if xbmcvfs.exists(torrentFile) and not os.path.exists(torrentFile):
+ if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
+ torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
+ xbmcvfs.copy(torrentUrl, torrentFile)
+ if os.path.exists(torrentFile):
+ self.torrentFile = torrentFile
+ return self.torrentFile
+
+ def md5(self, string):
+ hasher = hashlib.md5()
+ try:
+ hasher.update(string)
+ except:
+ hasher.update(string.encode('utf-8', 'ignore'))
+ return hasher.hexdigest()
+
+ def magnetToTorrent(self, magnet):
+ try:
+ from Libtorrent import Libtorrent
+ torrent = Libtorrent(self.storageDirectory, magnet)
+ torrent.magnetToTorrent(magnet)
+ self.torrentFile = torrent.torrentFile
+ except:
+ self.torrentFile = magnet
+ log('['+author+'Loader][magnetToTorrent]: self.torrentFile '+str(self.torrentFile))
+
+class AnteoPlayer(xbmc.Player):
+ __plugin__ = sys.modules["__main__"].__plugin__
+ __settings__ = sys.modules["__main__"].__settings__
+ ROOT = sys.modules["__main__"].__root__ # .decode('utf-8').encode(sys.getfilesystemencoding())
+ USERAGENT = "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0"
+ torrentFilesDirectory = 'torrents'
+ debug = __settings__.getSetting('debug') == 'true'
+ subs_dl = __settings__.getSetting('subs_dl') == 'true'
+ seeding = __settings__.getSetting('keep_seeding') == 'true' and __settings__.getSetting('keep_files') == '1'
+ seeding_status = False
+ seeding_run = False
+ ids_video = None
+ episodeId = None
+ fullSize = 0
+ watchedTime = 0
+ totalTime = 1
+ seek = 0
+ basename = ''
+
+ def __init__(self, userStorageDirectory, torrentUrl, params={}):
+ self.userStorageDirectory = userStorageDirectory
+ self.torrentUrl = torrentUrl
+ xbmc.Player.__init__(self)
+ log("[AnteoPlayer] Initalized")
+ self.params = params
+ self.get = self.params.get
+ self.contentId = int(self.get("url"))
+ if self.get("seek"):
+ self.seek = int(self.get("seek"))
+ #self.torrent = AnteoLoader(self.userStorageDirectory, self.torrentUrl, self.torrentFilesDirectory)
+ self.init()
+ self.setup_engine()
+ with closing(self.engine):
+ self.engine.start(self.contentId)
+ self.setup_nextep()
+ while True:
+ if self.buffer():
+ log('['+author+'Player]: ************************************* GOING LOOP')
+ if self.setup_play():
+ self.setup_subs()
+ self.loop()
+ WatchedHistoryDB().add(self.basename, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
+ else:
+ log('['+author+'Player]: ************************************* break')
+ break
+ log('['+author+'Player]: ************************************* GO NEXT?')
+ if self.next_dl and self.next_contentId != False and isinstance(self.next_contentId, int) and self.iterator == 100:
+ if not self.next_play:
+ xbmc.sleep(3000)
+ if not xbmcgui.Dialog().yesno(
+ self.localize('Torrent2HTTP'),
+ self.localize('Would you like to play next episode?')):
+ break
+ self.contentId = self.next_contentId
+ continue
+ log('['+author+'Player]: ************************************* NO! break')
+ break
+
+ xbmc.Player().stop()
+
+ if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.userStorageDirectory:
+ xbmc.sleep(1000)
+ clearStorage(self.userStorageDirectory)
+ else:
+ #if self.seeding_status:
+ #showMessage(self.localize('Information'),
+ # self.localize('Torrent is seeding. To stop it use Download Status.'), forced=True)
+ #else:
+ #if self.seeding: self.db_delete()
+ showMessage(self.localize('Information'),
+ self.localize('Torrent downloading is stopped.'), forced=True)
+
+ def __exit__(self):
+ log('on __exit__')
+ if self.engine:
+ self.engine.close()
+ log('__exit__ worked!')
+
+ def init(self):
+ self.next_contentId = False
+ self.display_name = ''
+ self.downloadedSize = 0
+ self.dialog = xbmcgui.Dialog()
+ self.on_playback_started = []
+ self.on_playback_resumed = []
+ self.on_playback_paused = []
+ self.on_playback_stopped = []
+ self.torrentUrl = self.torrentUrl
+
+ def setup_engine(self):
+ #uri=None, binaries_path=None, platform=None, download_path=".",
+ #bind_host='127.0.0.1', bind_port=5001, connections_limit=None, download_kbps=None, upload_kbps=None,
+ #enable_dht=True, enable_lsd=True, enable_natpmp=True, enable_upnp=True, enable_scrape=False,
+ #log_stats=False, encryption=Encryption.ENABLED, keep_complete=False, keep_incomplete=False,
+ #keep_files=False, log_files_progress=False, log_overall_progress=False, log_pieces_progress=False,
+ #listen_port=6881, use_random_port=False, max_idle_timeout=None, no_sparse=False, resume_file=None,
+ #user_agent=None, startup_timeout=5, state_file=None, enable_utp=True, enable_tcp=True,
+ #debug_alerts=False, logger=None, torrent_connect_boost=50, connection_speed=50,
+ #peer_connect_timeout=15, request_timeout=20, min_reconnect_time=60, max_failcount=3,
+ #dht_routers=None, trackers=None)
+
+ encryption = Encryption.ENABLED if self.__settings__.getSetting('encryption') == 'true' else Encryption.DISABLED
+ upload_limit = int(self.__settings__.getSetting("upload_limit"))*1024/8 if self.__settings__.getSetting(
+ "upload_limit") != "" else 0
+ download_limit = int(self.__settings__.getSetting("download_limit"))*1024/8 if self.__settings__.getSetting(
+ "download_limit") != "" else 0
+
+ if self.__settings__.getSetting("connections_limit") not in ["",0,"0"]:
+ connections_limit = int(self.__settings__.getSetting("connections_limit"))
+ else:
+ connections_limit = None
+
+ use_random_port = True if self.__settings__.getSetting('use_random_port') == 'true' else False
+
+ listen_port=int(self.__settings__.getSetting("listen_port")) if self.__settings__.getSetting(
+ "listen_port") != "" else 6881
+
+ if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.userStorageDirectory:
+ keep_complete = False
+ keep_incomplete = False
+ keep_files = False
+ resume_file = None
+ else:
+ keep_complete = True
+ keep_incomplete = True
+ keep_files = True
+ resume_file=os.path.join(self.userStorageDirectory, 'torrents', os.path.basename(self.torrentUrl)+'.resume_data')
+
+ dht_routers = ["router.bittorrent.com:6881","router.utorrent.com:6881"]
+ user_agent = 'uTorrent/2200(24683)'
+ self.pre_buffer_bytes = int(self.__settings__.getSetting("pre_buffer_bytes"))*1024*1024
+
+ self.engine = Engine(uri=file_url(self.torrentUrl), download_path=self.userStorageDirectory,
+ connections_limit=connections_limit, download_kbps=download_limit, upload_kbps=upload_limit,
+ encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
+ dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
+ keep_files=keep_files, user_agent=user_agent, resume_file=resume_file)
+
+ def buffer(self):
+ #self.pre_buffer_bytes = 30*1024*1024 #30 MB
+ ready = False
+ progressBar = xbmcgui.DialogProgress()
+ progressBar.create(self.localize('Please Wait'),
+ self.localize('Seeds searching.'))
+ #if self.subs_dl:
+ # subs = self.torrent.getSubsIds(os.path.basename(self.torrent.getFilePath(self.contentId)))
+ # if len(subs) > 0:
+ # for ind, title in subs:
+ # self.torrent.continueSession(ind)
+
+ while not xbmc.abortRequested and not ready:
+ xbmc.sleep(500)
+ status = self.engine.status()
+ self.print_debug(status)
+ #self.print_fulldebug()
+ self.engine.check_torrent_error(status)
+ file_status = self.engine.file_status(self.contentId)
+ if not file_status:
+ continue
+ self.fullSize = int(file_status.size / 1024 / 1024)
+ downloadedSize = status.total_download / 1024 / 1024
+ getDownloadRate = status.download_rate / 1024 * 8
+ getUploadRate = status.upload_rate / 1024 * 8
+ getSeeds, getPeers = status.num_seeds, status.num_peers
+ iterator = int(round(float(file_status.download) / self.pre_buffer_bytes, 2) * 100)
+ if iterator > 99: iterator = 99
+ if status.state == State.CHECKING_FILES:
+ iterator = int(status.progress*100)
+ if iterator > 99: iterator = 99
+ progressBar.update(iterator, self.localize('Checking preloaded files...'), ' ', ' ')
+ elif status.state == State.DOWNLOADING:
+ dialogText = self.localize('Preloaded: ') + "%d MB / %d MB" % \
+ (int(downloadedSize), self.fullSize)
+ peersText = ' [%s: %s; %s: %s]' % (
+ self.localize('Seeds'), getSeeds, self.localize('Peers'), getPeers)
+ speedsText = '%s: %d Mbit/s; %s: %d Mbit/s' % (
+ self.localize('Downloading'), int(getDownloadRate),
+ self.localize('Uploading'), int(getUploadRate))
+ progressBar.update(iterator, self.localize('Seeds searching.') + peersText, dialogText,
+ speedsText)
+
+ if file_status.download >= self.pre_buffer_bytes:
+ ready = True
+ break
+ elif status.state in [State.FINISHED, State.SEEDING]:
+ ready = True
+ break
+ else:
+ progressBar.update(iterator, self.localize('UNKNOWN STATUS'), ' ', ' ')
+ if progressBar.iscanceled():
+ self.iterator = 0
+ ready = False
+ break
+
+ progressBar.update(0)
+ progressBar.close()
+ return ready
+
+ def setup_nextep(self):
+ try:
+ if self.get("url2"):
+ debug("[setup_nextep]: url2")
+ self.ids_video = urllib.unquote_plus(self.get("url2")).split(',')
+ else:
+ debug("[setup_nextep]: not url2")
+ self.ids_video = self.get_ids()
+ except:
+ pass
+
+ if self.__settings__.getSetting('next_dl') == 'true' and self.ids_video and len(self.ids_video)>1:
+ self.next_dl = True
+ else:
+ self.next_dl = False
+ self.next_play = self.__settings__.getSetting('next_play') == 'true'
+ log('['+author+'Player]: next_dl - %s, next_play - %s, ids_video - %s' % (str(self.next_dl), str(self.next_play), str(self.ids_video)))
+
+ def setup_play(self):
+ file_status = self.engine.file_status(self.contentId)
+ self.iterator = 0
+ self.watchedTime = 0
+ self.totalTime = 1
+ url = file_status.url
+ label = os.path.basename(file_status.name)
+ self.basename = label
+ self.seeding_run = False
+ listitem = xbmcgui.ListItem(label, path=url)
+
+ if self.next_dl:
+ next_contentId_index = self.ids_video.index(str(self.contentId)) + 1
+ if len(self.ids_video) > next_contentId_index:
+ self.next_contentId = int(self.ids_video[next_contentId_index])
+ else:
+ self.next_contentId = False
+ log('['+author+'Player][setup_play]: next_contentId: '+str(self.next_contentId))
+ try:
+ seasonId = self.get("seasonId")
+ self.episodeId = self.get("episodeId") if not self.episodeId else int(self.episodeId) + 1
+ title = urllib.unquote_plus(self.get("title")) if self.get("title") else None
+
+ if self.get("label") and self.episodeId == self.get("episodeId"):
+ label = urllib.unquote_plus(self.get("label"))
+ elif seasonId and self.episodeId and title:
+ label = '%s S%02dE%02d.%s (%s)' % (
+ title, int(seasonId), int(self.episodeId), self.basename.split('.')[-1], self.basename)
+
+ if seasonId and self.episodeId and label and title:
+ listitem = xbmcgui.ListItem(label, path=url)
+
+ listitem.setInfo(type='video', infoLabels={'title': label,
+ 'episode': int(self.episodeId),
+ 'season': int(seasonId),
+ 'tvshowtitle': title})
+ except:
+ log('['+author+'Player]: Operation INFO failed!')
+
+ thumbnail = self.get("thumbnail")
+ if thumbnail:
+ listitem.setThumbnailImage(urllib.unquote_plus(thumbnail))
+ self.display_name = label
+
+ player = xbmc.Player()
+ player.play(url, listitem)
+
+ xbmc.sleep(2000) # very important, do not edit this, podavan
+ i = 0
+ while not xbmc.abortRequested and not self.isPlaying() and i < 50:
+ xbmc.sleep(200)
+ i += 1
+
+ log('['+author+'Player]: self.isPlaying() = %s, i = %d, xbmc.abortRequested - %s' % (str(self.isPlaying()), i, str(xbmc.abortRequested)))
+ if not self.isPlaying() or xbmc.abortRequested:
+ return False
+
+ if self.seek > 0:
+ log('['+author+'Player]: seekTime - '+str(self.seek))
+ self.seekTime(self.seek)
+ return True
+
+ def setup_subs(self):
+ if self.subs_dl:
+ file_status = self.engine.file_status(self.contentId)
+ subs = []
+ filename = os.path.basename(file_status.name)
+ sub_files = self.engine.list(media_types=[MediaType.SUBTITLES])
+ for i in sub_files:
+ if isSubtitle(filename, i.name):
+ subs.append(i)
+ if subs:
+ log("[AnteoPlayer][setup_subs]: Detected subtitles: %s" % str(subs))
+ for sub in subs:
+ xbmc.Player().setSubtitles(sub.url)
+
+ def loop(self):
+ debug_counter = 0
+ pause = True
+ with closing(
+ OverlayText(w=OVERLAY_WIDTH, h=OVERLAY_HEIGHT, alignment=XBFONT_CENTER_X | XBFONT_CENTER_Y)) as overlay:
+ with nested(self.attach(overlay.show, self.on_playback_paused),
+ self.attach(overlay.hide, self.on_playback_resumed, self.on_playback_stopped)):
+ while not xbmc.abortRequested and self.isPlaying():
+ #self.print_fulldebug()
+ status = self.engine.status()
+ file_status = self.engine.file_status(self.contentId)
+ self.watchedTime = xbmc.Player().getTime()
+ self.totalTime = xbmc.Player().getTotalTime()
+ if self.iterator == 100 and debug_counter < 100:
+ debug_counter += 1
+ else:
+ self.print_debug(status)
+ debug_counter=0
+
+ overlay.text = "\n".join(self._get_status_lines(status, file_status))
+
+ self.iterator = int(file_status.progress * 100)
+
+ if pause and self.__settings__.getSetting("pause_onplay") == 'true':
+ pause = False
+ xbmc.Player().pause()
+ xbmc.sleep(1000)
+
+ #if not self.seeding_run and self.iterator == 100 and self.seeding:
+ #self.seeding_run = True
+ #self.seed(self.contentId)
+ #self.seeding_status = True
+ # xbmc.sleep(7000)
+
+ def onPlayBackStarted(self):
+ for f in self.on_playback_started:
+ f()
+ log('[onPlayBackStarted]: '+(str(("video", "play", self.display_name))))
+
+ def onPlayBackResumed(self):
+ for f in self.on_playback_resumed:
+ f()
+ self.onPlayBackStarted()
+
+ def onPlayBackPaused(self):
+ for f in self.on_playback_paused:
+ f()
+ log('[onPlayBackPaused]: '+(str(("video", "pause", self.display_name))))
+
+ def onPlayBackStopped(self):
+ for f in self.on_playback_stopped:
+ f()
+ log('[onPlayBackStopped]: '+(str(("video", "stop", self.display_name))))
+
+ @contextmanager
+ def attach(self, callback, *events):
+ for event in events:
+ event.append(callback)
+ yield
+ for event in events:
+ event.remove(callback)
+
+ def _get_status_lines(self, s, f):
+ return [
+ self.display_name,
+ "%.2f%% %s" % (f.progress * 100, self.localize(STATE_STRS[s.state]).decode('utf-8')),
+ "D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate, self.localize('kb/s').decode('utf-8'),
+ s.upload_rate, self.localize('kb/s').decode('utf-8'),
+ s.num_seeds, s.num_peers)
+ ]
+
+ def localize(self, string):
+ try:
+ return Localization.localize(string)
+ except:
+ return string
+
+ def print_debug(self, status=None):
+ #FileStatus = namedtuple('FileStatus', "name, save_path, url, size, offset, download, progress, index, media_type")
+
+ #SessionStatus = namedtuple('SessionStatus', "name, state, state_str, error, progress, download_rate, upload_rate, "
+ # "total_download, total_upload, num_peers, num_seeds, total_seeds, "
+ # "total_peers")
+
+ #log('[buffer] file_status:'+str(file_status))
+ #log('[buffer] status:'+str(status))
+ if not status:
+ status = self.engine.status()
+ self.engine.check_torrent_error(status)
+ log('['+author+'Player]: %.2f%% complete (down: %.1f kb/s up: %.1f kb/s peers: %d) %s' % \
+ (status.progress * 100, status.download_rate,
+ status.upload_rate, status.num_peers, status.state_str))
+
+ def print_fulldebug(self):
+ status = self.engine.status()
+ file_status = self.engine.file_status(self.contentId)
+ log('[buffer] file_status:'+str(file_status))
+ log('[buffer] status:'+str(status))
+
+ def get_ids(self):
+ contentList = []
+ for fs in self.engine.list():
+ contentList.append((fs.name, str(fs.index)))
+ contentList = sorted(contentList, key=lambda x: x[0])
+ return get_ids_video(contentList)
+
+ def getContentList(self):
+ filelist = []
+ for fs in self.engine.list():
+ stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
+ 'offset': fs.offset}
+ filelist.append(stringdata)
+ return filelist
+
+class OverlayText(object):
+ def __init__(self, w, h, *args, **kwargs):
+ self.window = xbmcgui.Window(WINDOW_FULLSCREEN_VIDEO)
+ viewport_w, viewport_h = self._get_skin_resolution()
+ # Adjust size based on viewport, we are using 1080p coordinates
+ w = int(w * viewport_w / VIEWPORT_WIDTH)
+ h = int(h * viewport_h / VIEWPORT_HEIGHT)
+ x = (viewport_w - w) / 2
+ y = (viewport_h - h) / 2
+ self._shown = False
+ self._text = ""
+ self._label = xbmcgui.ControlLabel(x, y, w, h, self._text, *args, **kwargs)
+ self._background = xbmcgui.ControlImage(x, y, w, h, os.path.join(RESOURCES_PATH, "images", "black.png"))
+ self._background.setColorDiffuse("0xD0000000")
+
+ def show(self):
+ if not self._shown:
+ self.window.addControls([self._background, self._label])
+ self._shown = True
+ self._background.setColorDiffuse("0xD0000000")
+
+ def hide(self):
+ if self._shown:
+ self._shown = False
+ self.window.removeControls([self._background, self._label])
+ self._background.setColorDiffuse("0xFF000000")
+
+ def close(self):
+ self.hide()
+
+ @property
+ def text(self):
+ return self._text
+
+ @text.setter
+ def text(self, text):
+ self._text = text
+ if self._shown:
+ self._label.setLabel(self._text)
+
+ # This is so hackish it hurts.
+ def _get_skin_resolution(self):
+ import xml.etree.ElementTree as ET
+
+ skin_path = xbmc.translatePath("special://skin/")
+ tree = ET.parse(os.path.join(skin_path, "addon.xml"))
+ res = tree.findall("./extension/res")[0]
return int(res.attrib["width"]), int(res.attrib["height"])
\ No newline at end of file
diff --git a/Libtorrent.py b/Libtorrent.py
index fed73c5..25c863b 100644
--- a/Libtorrent.py
+++ b/Libtorrent.py
@@ -1,607 +1,607 @@
-# -*- coding: utf-8 -*-
-'''
- Torrenter v2 plugin for XBMC/Kodi
- Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
- https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-'''
-
-import thread
-import os
-import urllib2
-import hashlib
-import re
-from StringIO import StringIO
-import gzip
-import sys
-
-import xbmc
-import xbmcgui
-import xbmcvfs
-import Localization
-from functions import file_encode, isSubtitle, DownloadDB, log, debug, is_writable, vista_check, windows_check
-from platform_pulsar import get_platform
-
-class Libtorrent:
- magnetLink = None
- startPart = 0
- endPart = 0
- partOffset = 0
- torrentHandle = None
- session = None
- downloadThread = None
- threadComplete = False
- lt = None
- save_resume_data = None
- __settings__ = sys.modules["__main__"].__settings__
-
- def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
- self.platform = get_platform()
- self.storageDirectory = storageDirectory
- self.torrentFilesPath = os.path.join(self.storageDirectory, torrentFilesDirectory) + os.sep
- if not is_writable(self.storageDirectory):
- xbmcgui.Dialog().ok(Localization.localize('Torrenter v2'),
- Localization.localize('Your storage path is not writable or not local! Please change it in settings!'),
- Localization.localize(self.storageDirectory))
-
- sys.exit(1)
-
- try:
- from python_libtorrent import get_libtorrent
- libtorrent=get_libtorrent()
- log('Imported libtorrent v%s from python_libtorrent/%s' %(libtorrent.version, self.platform['system']))
- module=True
- except Exception, e:
- module=False
- log('Error importing python_libtorrent.%s. Exception: %s' %(self.platform['system'], str(e)))
- import libtorrent
-
- try:
- if not module: log('Imported libtorrent v' + libtorrent.version + ' from system')
- self.lt = libtorrent
- del libtorrent
-
- except Exception, e:
- log('Error importing from system. Exception: ' + str(e))
- xbmcgui.Dialog().ok(Localization.localize('python-libtorrent Not Found'),
- Localization.localize(self.platform["message"][0]),
- Localization.localize(self.platform["message"][1]))
- return
-
- if xbmcvfs.exists(torrentFile):
- self.torrentFile = torrentFile
- e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
- self.torrentFileInfo = self.lt.torrent_info(e)
- elif re.match("^magnet\:.+$", torrentFile):
- self.magnetLink = torrentFile
-
- def saveTorrent(self, torrentUrl):
- if re.match("^magnet\:.+$", torrentUrl):
- self.magnetLink = torrentUrl
- self.magnetToTorrent(torrentUrl)
- self.magnetLink = None
- return self.torrentFile
- else:
- if not xbmcvfs.exists(self.torrentFilesPath):
- xbmcvfs.mkdirs(self.torrentFilesPath)
- torrentFile = self.torrentFilesPath + self.md5(
- torrentUrl) + '.torrent'
- try:
- if not re.match("^http\:.+$", torrentUrl):
- content = xbmcvfs.File(torrentUrl, "rb").read()
- else:
- request = urllib2.Request(torrentUrl)
- request.add_header('Referer', torrentUrl)
- request.add_header('Accept-encoding', 'gzip')
- result = urllib2.urlopen(request)
- if result.info().get('Content-Encoding') == 'gzip':
- buf = StringIO(result.read())
- f = gzip.GzipFile(fileobj=buf)
- content = f.read()
- else:
- content = result.read()
-
- localFile = xbmcvfs.File(torrentFile, "w+b")
- localFile.write(content)
- localFile.close()
- except Exception, e:
- log('Unable to save torrent file from "' + torrentUrl + '" to "' + torrentFile + '" in Torrent::saveTorrent' + '. Exception: ' + str(e))
- return
- if xbmcvfs.exists(torrentFile):
- try:
- e=self.lt.bdecode(xbmcvfs.File(torrentFile,'rb').read())
- self.torrentFileInfo = self.lt.torrent_info(e)
- except Exception, e:
- log('Exception: ' + str(e))
- xbmcvfs.delete(torrentFile)
- return
- baseName = file_encode(os.path.basename(self.getFilePath()))
- if not xbmcvfs.exists(self.torrentFilesPath):
- xbmcvfs.mkdirs(self.torrentFilesPath)
- newFile = self.torrentFilesPath + self.md5(baseName) + '.' + self.md5(
- torrentUrl) + '.torrent' # + '.'+ baseName
- if xbmcvfs.exists(newFile):
- xbmcvfs.delete(newFile)
- if not xbmcvfs.exists(newFile):
- try:
- xbmcvfs.rename(torrentFile, newFile)
- except Exception, e:
- log('Unable to rename torrent file from %s to %s in Torrent::renameTorrent. Exception: %s' %
- (torrentFile, newFile, str(e)))
- return
- self.torrentFile = newFile
- if not self.torrentFileInfo:
- e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
- self.torrentFileInfo = self.lt.torrent_info(e)
- return self.torrentFile
-
- def getMagnetInfo(self):
- magnetSettings = {
- 'url': self.magnetLink,
- 'save_path': self.storageDirectory,
- 'storage_mode': self.lt.storage_mode_t(0),
- 'paused': True,
- #'auto_managed': True,
- #'duplicate_is_error': True
- }
- progressBar = xbmcgui.DialogProgress()
- progressBar.create(Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting'))
- #try:
- self.torrentHandle = self.session.add_torrent(magnetSettings)
- #except:
- # self.torrentHandle = self.lt.add_magnet_uri(self.session, self.magnetLink, magnetSettings)
- iterator = 0
- while iterator < 100:
- xbmc.sleep(500)
- self.torrentHandle.force_dht_announce()
- progressBar.update(iterator, Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting')+'.' * (iterator % 4), ' ')
- iterator += 1
- if progressBar.iscanceled():
- progressBar.update(0)
- progressBar.close()
- return
- if self.torrentHandle.status().has_metadata:
- iterator = 100
- progressBar.update(0)
- progressBar.close()
- if self.torrentHandle.status().has_metadata:
- try:
- info = self.torrentHandle.torrent_file()
- except:
- info = self.torrentHandle.get_torrent_info()
- return info
-
- def magnetToTorrent(self, magnet):
- self.magnetLink = magnet
- self.initSession()
- torrentInfo = self.getMagnetInfo()
- if torrentInfo:
- try:
- torrentFile = self.lt.create_torrent(torrentInfo)
- baseName = os.path.basename(self.storageDirectory + os.sep + torrentInfo.files()[0].path)
- if not xbmcvfs.exists(self.torrentFilesPath):
- xbmcvfs.mkdirs(self.torrentFilesPath)
- self.torrentFile = self.torrentFilesPath + self.md5(baseName) + '.torrent'
- torentFileHandler = xbmcvfs.File(self.torrentFile, "w+b")
- torentFileHandler.write(self.lt.bencode(torrentFile.generate()))
- torentFileHandler.close()
- e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
- self.torrentFileInfo = self.lt.torrent_info(e)
- except:
- xbmc.executebuiltin("Notification(%s, %s, 7500)" % (Localization.localize('Error'), Localization.localize(
- 'Can\'t download torrent, probably no seeds available.')))
- self.torrentFileInfo = torrentInfo
- finally:
- self.session.remove_torrent(self.torrentHandle)
- self.torrentHandle = None
-
- def getUploadRate(self):
- if None == self.torrentHandle:
- return 0
- else:
- return self.torrentHandle.status().upload_payload_rate
-
- def getDownloadRate(self):
- if None == self.torrentHandle:
- return 0
- else:
- return self.torrentHandle.status().download_payload_rate
-
- def getPeers(self):
- if None == self.torrentHandle:
- return 0
- else:
- return self.torrentHandle.status().num_peers
-
- def getSeeds(self):
- if None == self.torrentHandle:
- return 0
- else:
- return self.torrentHandle.status().num_seeds
-
- def getFileSize(self, contentId=0):
- return self.getContentList()[contentId]['size']
-
- def getFilePath(self, contentId=0):
- return os.path.join(self.storageDirectory, self.getContentList()[contentId]['title']) # .decode('utf8')
-
- def getContentList(self):
- filelist = []
- for contentId, contentFile in enumerate(self.torrentFileInfo.files()):
- stringdata = {"title": contentFile.path, "size": contentFile.size, "ind": int(contentId),
- 'offset': contentFile.offset}
- filelist.append(stringdata)
- return filelist
-
- def getSubsIds(self, filename):
- subs = []
- for i in self.getContentList():
- if isSubtitle(filename, i['title']):
- subs.append((i['ind'], i['title']))
- return subs
-
- def setUploadLimit(self, bytesPerSecond):
- try:
- session_settings = self.session.get_settings()
- session_settings['upload_rate_limit'] = int(bytesPerSecond)
- self.session.set_settings(session_settings)
- except:
- #0.16 compatibility
- self.session.set_upload_rate_limit(int(bytesPerSecond))
-
- def setDownloadLimit(self, bytesPerSecond):
- try:
- session_settings = self.session.get_settings()
- session_settings['download_rate_limit'] = int(bytesPerSecond)
- self.session.set_settings(session_settings)
- except:
- #0.16 compatibility
- self.session.set_download_rate_limit(int(bytesPerSecond))
-
- def md5(self, string):
- hasher = hashlib.md5()
- try:
- hasher.update(string)
- except:
- hasher.update(string.encode('utf-8', 'ignore'))
- return hasher.hexdigest()
-
- def downloadProcess(self, contentId, encrytion=True):
- self.initSession()
- if encrytion:
- self.encryptSession()
- self.startSession()
- self.paused = False
- db = DownloadDB()
- ContentList = self.getContentList()
- if contentId != None: contentId = int(contentId)
- if len(ContentList) == 1 or contentId not in [None, -1]:
- if not contentId: contentId = 0
- title = os.path.basename(ContentList[contentId]['title'])
- path = os.path.join(self.storageDirectory, ContentList[contentId]['title'])
- type = 'file'
- else:
- contentId = -1
- title = ContentList[0]['title'].split('\\')[0]
- path = os.path.join(self.storageDirectory, title)
- type = 'folder'
-
- add = db.add(title, path, type, {'progress': 0}, 'downloading', self.torrentFile, contentId,
- self.storageDirectory)
- get = db.get(title)
- if add or get[5] == 'stopped':
- if get[5] == 'stopped':
- db.update_status(get[0], 'downloading')
- if contentId not in [None, -1]:
- self.continueSession(int(contentId), Offset=0, seeding=False)
- else:
- for i in range(self.torrentFileInfo.num_pieces()):
- self.torrentHandle.piece_priority(i, 6)
- thread.start_new_thread(self.downloadLoop, (title,))
-
- def downloadLoop(self, title):
- db = DownloadDB()
- status = 'downloading'
- while db.get(title) and status != 'stopped':
- xbmc.sleep(3000)
- status = db.get_status(title)
- if not self.paused:
- if status == 'pause':
- self.paused = True
- self.session.pause()
- else:
- if status != 'pause':
- self.paused = False
- self.session.resume()
- s = self.torrentHandle.status()
- info = {}
- info['upload'] = s.upload_payload_rate
- info['download'] = s.download_payload_rate
- info['peers'] = s.num_peers
- info['seeds'] = s.num_seeds
- iterator = int(s.progress * 100)
- info['progress'] = iterator
- db.update(title, info)
- self.debug()
- self.session.remove_torrent(self.torrentHandle)
- return
-
- def initSession(self):
- self.session = self.lt.session()
- self.session.set_alert_mask(self.lt.alert.category_t.error_notification | self.lt.alert.category_t.status_notification | self.lt.alert.category_t.storage_notification)
- #self.session.set_alert_mask(self.lt.alert.category_t.all_categories)
- self.session.add_dht_router("router.bittorrent.com", 6881)
- self.session.add_dht_router("router.utorrent.com", 6881)
- self.session.start_dht()
- self.session.start_lsd()
- self.session.start_upnp()
- self.session.start_natpmp()
- try:
- port = int(self.__settings__.getSetting('listen_port'))
- self.session.listen_on(port, port+10)
- except:
- try:
- log('listen_on(%d, %d) error' %(port, port+10))
- except:
- log('listen_port %s error' %(self.__settings__.getSetting('listen_port')))
-
- pc_config = int(self.__settings__.getSetting('pc_config'))
-
- # Session settings
- try:
- session_settings = self.session.get_settings()
- #
- session_settings['announce_to_all_tiers'] = True
- session_settings['announce_to_all_trackers'] = True
- session_settings['peer_connect_timeout'] = 2
- session_settings['rate_limit_ip_overhead'] = True
- session_settings['request_timeout'] = 1
- session_settings['torrent_connect_boost'] = 50
- session_settings['user_agent'] = 'uTorrent/2200(24683)'
- if pc_config == 0:
- #good pc
- session_settings['connections_limit'] = 200
- session_settings['unchoke_slots_limit'] = 10
- session_settings['connection_speed'] = 200
- session_settings['file_pool_size'] = 40
- elif pc_config == 1:
- #bad pc/router
- session_settings['connections_limit'] = 100
- session_settings['half_open_limit'] = (lambda: windows_check() and
- (lambda: vista_check() and 4 or 8)() or 50)()
- session_settings['unchoke_slots_limit'] = 4
- session_settings['connection_speed'] = 100
- session_settings['file_pool_size'] = 40
-
- #session_settings['cache_size'] = 0
- #session_settings['use_read_cache'] = False
-
- except:
- #0.15 compatibility
- log('[initSession]: Session settings 0.15 compatibility')
- session_settings = self.session.settings()
-
- session_settings.announce_to_all_tiers = True
- session_settings.announce_to_all_trackers = True
- session_settings.connection_speed = 100
- session_settings.peer_connect_timeout = 2
- session_settings.rate_limit_ip_overhead = True
- session_settings.request_timeout = 1
- session_settings.torrent_connect_boost = 100
- session_settings.user_agent = 'uTorrent/2200(24683)'
- #
- self.session.set_settings(session_settings)
-
- def encryptSession(self):
- # Encryption settings
- log('Encryption enabling...')
- try:
- encryption_settings = self.lt.pe_settings()
- encryption_settings.out_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced)
- encryption_settings.in_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced)
- encryption_settings.allowed_enc_level = self.lt.enc_level.both
- encryption_settings.prefer_rc4 = True
- self.session.set_pe_settings(encryption_settings)
- log('Encryption on!')
- except Exception, e:
- log('Encryption failed! Exception: ' + str(e))
- pass
-
- def startSession(self):
- if self.magnetLink:
- self.torrentFileInfo = self.getMagnetInfo()
- torrent_info={'ti': self.torrentFileInfo,
- 'save_path': self.storageDirectory,
- 'flags': 0x300,
- #'storage_mode': self.lt.storage_mode_t(1),
- 'paused': False,
- #'auto_managed': False,
- 'duplicate_is_error': False
- }
- if self.save_resume_data:
- log('loading resume data')
- torrent_info['resume_data']=self.save_resume_data
- else:
- resume_file=self.resume_data_path()
- if xbmcvfs.exists(resume_file):
- log('loading resume data from file '+resume_file)
- try:
- resumDataFile=xbmcvfs.File(resume_file,'rb')
- self.save_resume_data=resumDataFile.read()
- resumDataFile.close()
- torrent_info['resume_data']=self.save_resume_data
-
- except:
- log('Failed to load resume data from file '+ resume_file)
- self.torrentHandle = self.session.add_torrent(torrent_info)
- self.torrentHandle.set_sequential_download(True)
- self.torrentHandle.set_max_connections(60)
- self.torrentHandle.set_max_uploads(-1)
- self.stopSession()
-
- def stopSession(self):
- for i in range(self.torrentFileInfo.num_pieces()):
- self.torrentHandle.piece_priority(i, 0)
-
- def continueSession(self, contentId=0, Offset=0, seeding=False, isMP4=False):
- self.piece_length = self.torrentFileInfo.piece_length()
- selectedFileInfo = self.getContentList()[contentId]
- if not Offset:
- Offset = selectedFileInfo['size'] / (1024 * 1024)
- self.partOffset = (Offset * 1024 * 1024 / self.piece_length) + 1
- self.startPart = selectedFileInfo['offset'] / self.piece_length
- self.endPart = int((selectedFileInfo['offset'] + selectedFileInfo['size']) / self.piece_length)
- multiplier = self.partOffset / 5
- log('continueSession: multiplier ' + str(multiplier))
- for i in range(self.startPart, self.startPart + self.partOffset):
- if i <= self.endPart:
- self.torrentHandle.piece_priority(i, 7)
- if isMP4 and i % multiplier == 0:
- self.torrentHandle.piece_priority(self.endPart - i / multiplier, 7)
- if multiplier >= i:
- self.torrentHandle.piece_priority(self.endPart - i, 7)
-
- def checkThread(self):
- if self.threadComplete == True:
- self.resume_data()
- log('checkThread KIIIIIIIIIIILLLLLLLLLLLLLLL')
- try:
- self.session.remove_torrent(self.torrentHandle)
- except:
- log('RuntimeError: invalid torrent handle used')
- self.session.stop_natpmp()
- self.session.stop_upnp()
- self.session.stop_lsd()
- self.session.stop_dht()
-
- def resume_data(self):
- wasPaused=self.session.is_paused()
- self.session.pause()
- self.save_resume_data=None
-
- try:
- if not self.torrentHandle.is_valid():
- return
- status = self.torrentHandle.status()
- if not status.has_metadata:
- return
- if not status.need_save_resume:
- return
-
- log('[save_resume_data]: waiting for alert...')
- self.torrentHandle.save_resume_data(self.lt.save_resume_flags_t.flush_disk_cache)
- received=False
- while not received:
- self.session.wait_for_alert(1000)
- a = self.session.pop_alert()
- log('[save_resume_data]: ['+str(type(a))+'] the alert '+str(a)+' is received')
- if type(a) == self.lt.save_resume_data_alert:
- received = True
- debug('[save_resume_data]: '+str(dir(a)))
- self.save_resume_data=self.lt.bencode(a.resume_data)
- log('[save_resume_data]: the torrent resume data are received')
- try:
- resumeFileHandler = xbmcvfs.File(self.resume_data_path(), "w+b")
- resumeFileHandler.write(self.save_resume_data)
- resumeFileHandler.close()
- log('[save_resume_data]: the torrent resume data to file' + self.resume_data_path())
- except:
- log('[save_resume_data]: failed to save the torrent resume data to file')
- elif type(a) == self.lt.save_resume_data_failed_alert:
- received = True
- log('[save_resume_data]: save_resume_data() failed')
- log('[save_resume_data]: done.')
-
- finally:
- if not wasPaused:
- self.session.resume()
-
- def debug(self):
- #try:
- if 1==1:
- # log(str(self.getFilePath(0)))
- s = self.torrentHandle.status()
- #get_cache_status=self.session.get_cache_status()
- #log('get_cache_status - %s/%s' % (str(get_cache_status.blocks_written), str(get_cache_status.blocks_read)))
- # get_settings=self.torrentHandle.status
- # log(s.num_pieces)
- #priorities = self.torrentHandle.piece_priorities()
- #log(str(priorities))
-
- state_str = ['queued', 'checking', 'downloading metadata',
- 'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
- log('[%s] %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \
- (self.lt.version, s.progress * 100, s.download_rate / 1000,
- s.upload_rate / 1000, s.num_peers, state_str[s.state]))
- #log('%s %s' % (self.get_debug_info('dht_state'), self.get_debug_info('trackers_sum')))
- #debug('TRACKERS:' +str(self.torrentHandle.trackers()))
-
- #received=self.session.pop_alert()
- #while received:
- # debug('[debug]: ['+str(type(received))+'] the alert '+str(received)+' is received')
- # #if type(received) == self.lt.torrent_finished_alert:
- # # self.session.pause()
- # received = self.session.pop_alert()
-
- #log('is_dht_running:' +str(self.session.is_dht_running()))
- #log('dht_state:' +str(self.session.dht_state()))
- #i = 0
- # for t in s.pieces:
- # if t: i=i+1
- #log(str(self.session.pop_alert())
- # log(str(s.pieces[self.startPart:self.endPart]))
- # log('True pieces: %d' % i)
- # log(s.current_tracker)
- # log(str(s.pieces))
- #except:
- else:
- log('debug error')
- pass
-
- def get_debug_info(self, info):
- result=''
- if info in ['trackers_full','trackers_sum']:
- trackers=[]
- for tracker in self.torrentHandle.trackers():
- trackers.append((tracker['url'], tracker['fails'], tracker['verified']))
- if info=='trackers_full':
- for url, fails, verified in trackers:
- result=result+'%s: f=%d, v=%s' %(url, fails, str(verified))
- if info=='trackers_sum':
- fails_sum, verified_sum = 0, 0
- for url, fails, verified in trackers:
- fails_sum+=fails
- if verified: verified_sum+=1
- result=result+'Trackers: verified %d/%d, fails=%d' %(verified_sum, len(trackers)-1, fails_sum)
- if info=='dht_state':
- is_dht_running='ON' if self.session.is_dht_running() else 'OFF'
- try:
- nodes=self.session.dht_state().get('nodes')
- except:
- nodes=None
- nodes=len(nodes) if nodes else 0
- result='DHT: %s (%d)' % (is_dht_running, nodes)
- return result
-
- def dump(self, obj):
- for attr in dir(obj):
- try:
- log("'%s':'%s'," % (attr, getattr(obj, attr)))
- except:
- pass
-
- def resume_data_path(self):
- path=self.torrentFile + ".resume_data"
- return path
+# -*- coding: utf-8 -*-
+'''
+ Torrenter v2 plugin for XBMC/Kodi
+ Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
+ https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+'''
+
+import thread
+import os
+import urllib2
+import hashlib
+import re
+from StringIO import StringIO
+import zlib
+import sys
+
+import xbmc
+import xbmcgui
+import xbmcvfs
+import Localization
+from functions import file_encode, isSubtitle, DownloadDB, log, debug, is_writable, vista_check, windows_check
+from platform_pulsar import get_platform
+
+class Libtorrent:
+ magnetLink = None
+ startPart = 0
+ endPart = 0
+ partOffset = 0
+ torrentHandle = None
+ session = None
+ downloadThread = None
+ threadComplete = False
+ lt = None
+ save_resume_data = None
+ __settings__ = sys.modules["__main__"].__settings__
+
+ def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
+ self.platform = get_platform()
+ self.storageDirectory = storageDirectory
+ self.torrentFilesPath = os.path.join(self.storageDirectory, torrentFilesDirectory) + os.sep
+ if not is_writable(self.storageDirectory):
+ xbmcgui.Dialog().ok(Localization.localize('Torrenter v2'),
+ Localization.localize('Your storage path is not writable or not local! Please change it in settings!'),
+ Localization.localize(self.storageDirectory))
+
+ sys.exit(1)
+
+ try:
+ from python_libtorrent import get_libtorrent
+ libtorrent=get_libtorrent()
+ log('Imported libtorrent v%s from python_libtorrent/%s' %(libtorrent.version, self.platform['system']))
+ module=True
+ except Exception, e:
+ module=False
+ log('Error importing python_libtorrent.%s. Exception: %s' %(self.platform['system'], str(e)))
+ import libtorrent
+
+ try:
+ if not module: log('Imported libtorrent v' + libtorrent.version + ' from system')
+ self.lt = libtorrent
+ del libtorrent
+
+ except Exception, e:
+ log('Error importing from system. Exception: ' + str(e))
+ xbmcgui.Dialog().ok(Localization.localize('python-libtorrent Not Found'),
+ Localization.localize(self.platform["message"][0]),
+ Localization.localize(self.platform["message"][1]))
+ return
+
+ if xbmcvfs.exists(torrentFile):
+ self.torrentFile = torrentFile
+ e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
+ self.torrentFileInfo = self.lt.torrent_info(e)
+ elif re.match("^magnet\:.+$", torrentFile):
+ self.magnetLink = torrentFile
+
+ def saveTorrent(self, torrentUrl):
+ if re.match("^magnet\:.+$", torrentUrl):
+ self.magnetLink = torrentUrl
+ self.magnetToTorrent(torrentUrl)
+ self.magnetLink = None
+ return self.torrentFile
+ else:
+ if not xbmcvfs.exists(self.torrentFilesPath):
+ xbmcvfs.mkdirs(self.torrentFilesPath)
+ torrentFile = self.torrentFilesPath + self.md5(
+ torrentUrl) + '.torrent'
+ try:
+ if not re.match("^http\:.+$", torrentUrl):
+ content = xbmcvfs.File(torrentUrl, "rb").read()
+ else:
+ request = urllib2.Request(torrentUrl)
+ request.add_header('Referer', torrentUrl)
+ request.add_header('Accept-encoding', 'gzip')
+ result = urllib2.urlopen(request)
+ if result.info().get('Content-Encoding') == 'gzip':
+ buf = StringIO(result.read())
+ decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
+ content = decomp.decompress(buf.getvalue())
+ else:
+ content = result.read()
+
+ localFile = xbmcvfs.File(torrentFile, "w+b")
+ localFile.write(content)
+ localFile.close()
+ except Exception, e:
+ log('Unable to save torrent file from "' + torrentUrl + '" to "' + torrentFile + '" in Torrent::saveTorrent' + '. Exception: ' + str(e))
+ return
+ if xbmcvfs.exists(torrentFile):
+ try:
+ e=self.lt.bdecode(xbmcvfs.File(torrentFile,'rb').read())
+ self.torrentFileInfo = self.lt.torrent_info(e)
+ except Exception, e:
+ log('Exception: ' + str(e))
+ xbmcvfs.delete(torrentFile)
+ return
+ baseName = file_encode(os.path.basename(self.getFilePath()))
+ if not xbmcvfs.exists(self.torrentFilesPath):
+ xbmcvfs.mkdirs(self.torrentFilesPath)
+ newFile = self.torrentFilesPath + self.md5(baseName) + '.' + self.md5(
+ torrentUrl) + '.torrent' # + '.'+ baseName
+ if xbmcvfs.exists(newFile):
+ xbmcvfs.delete(newFile)
+ if not xbmcvfs.exists(newFile):
+ try:
+ xbmcvfs.rename(torrentFile, newFile)
+ except Exception, e:
+ log('Unable to rename torrent file from %s to %s in Torrent::renameTorrent. Exception: %s' %
+ (torrentFile, newFile, str(e)))
+ return
+ self.torrentFile = newFile
+ if not self.torrentFileInfo:
+ e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
+ self.torrentFileInfo = self.lt.torrent_info(e)
+ return self.torrentFile
+
+ def getMagnetInfo(self):
+ magnetSettings = {
+ 'url': self.magnetLink,
+ 'save_path': self.storageDirectory,
+ 'storage_mode': self.lt.storage_mode_t(0),
+ 'paused': True,
+ #'auto_managed': True,
+ #'duplicate_is_error': True
+ }
+ progressBar = xbmcgui.DialogProgress()
+ progressBar.create(Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting'))
+ #try:
+ self.torrentHandle = self.session.add_torrent(magnetSettings)
+ #except:
+ # self.torrentHandle = self.lt.add_magnet_uri(self.session, self.magnetLink, magnetSettings)
+ iterator = 0
+ while iterator < 100:
+ xbmc.sleep(500)
+ self.torrentHandle.force_dht_announce()
+ progressBar.update(iterator, Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting')+'.' * (iterator % 4), ' ')
+ iterator += 1
+ if progressBar.iscanceled():
+ progressBar.update(0)
+ progressBar.close()
+ return
+ if self.torrentHandle.status().has_metadata:
+ iterator = 100
+ progressBar.update(0)
+ progressBar.close()
+ if self.torrentHandle.status().has_metadata:
+ try:
+ info = self.torrentHandle.torrent_file()
+ except:
+ info = self.torrentHandle.get_torrent_info()
+ return info
+
+ def magnetToTorrent(self, magnet):
+ self.magnetLink = magnet
+ self.initSession()
+ torrentInfo = self.getMagnetInfo()
+ if torrentInfo:
+ try:
+ torrentFile = self.lt.create_torrent(torrentInfo)
+ baseName = os.path.basename(self.storageDirectory + os.sep + torrentInfo.files()[0].path)
+ if not xbmcvfs.exists(self.torrentFilesPath):
+ xbmcvfs.mkdirs(self.torrentFilesPath)
+ self.torrentFile = self.torrentFilesPath + self.md5(baseName) + '.torrent'
+ torentFileHandler = xbmcvfs.File(self.torrentFile, "w+b")
+ torentFileHandler.write(self.lt.bencode(torrentFile.generate()))
+ torentFileHandler.close()
+ e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
+ self.torrentFileInfo = self.lt.torrent_info(e)
+ except:
+ xbmc.executebuiltin("Notification(%s, %s, 7500)" % (Localization.localize('Error'), Localization.localize(
+ 'Can\'t download torrent, probably no seeds available.')))
+ self.torrentFileInfo = torrentInfo
+ finally:
+ self.session.remove_torrent(self.torrentHandle)
+ self.torrentHandle = None
+
+ def getUploadRate(self):
+ if None == self.torrentHandle:
+ return 0
+ else:
+ return self.torrentHandle.status().upload_payload_rate
+
+ def getDownloadRate(self):
+ if None == self.torrentHandle:
+ return 0
+ else:
+ return self.torrentHandle.status().download_payload_rate
+
+ def getPeers(self):
+ if None == self.torrentHandle:
+ return 0
+ else:
+ return self.torrentHandle.status().num_peers
+
+ def getSeeds(self):
+ if None == self.torrentHandle:
+ return 0
+ else:
+ return self.torrentHandle.status().num_seeds
+
+ def getFileSize(self, contentId=0):
+ return self.getContentList()[contentId]['size']
+
+ def getFilePath(self, contentId=0):
+ return os.path.join(self.storageDirectory, self.getContentList()[contentId]['title']) # .decode('utf8')
+
+ def getContentList(self):
+ filelist = []
+ for contentId, contentFile in enumerate(self.torrentFileInfo.files()):
+ stringdata = {"title": contentFile.path, "size": contentFile.size, "ind": int(contentId),
+ 'offset': contentFile.offset}
+ filelist.append(stringdata)
+ return filelist
+
+ def getSubsIds(self, filename):
+ subs = []
+ for i in self.getContentList():
+ if isSubtitle(filename, i['title']):
+ subs.append((i['ind'], i['title']))
+ return subs
+
+ def setUploadLimit(self, bytesPerSecond):
+ try:
+ session_settings = self.session.get_settings()
+ session_settings['upload_rate_limit'] = int(bytesPerSecond)
+ self.session.set_settings(session_settings)
+ except:
+ #0.16 compatibility
+ self.session.set_upload_rate_limit(int(bytesPerSecond))
+
+ def setDownloadLimit(self, bytesPerSecond):
+ try:
+ session_settings = self.session.get_settings()
+ session_settings['download_rate_limit'] = int(bytesPerSecond)
+ self.session.set_settings(session_settings)
+ except:
+ #0.16 compatibility
+ self.session.set_download_rate_limit(int(bytesPerSecond))
+
+ def md5(self, string):
+ hasher = hashlib.md5()
+ try:
+ hasher.update(string)
+ except:
+ hasher.update(string.encode('utf-8', 'ignore'))
+ return hasher.hexdigest()
+
+ def downloadProcess(self, contentId, encrytion=True):
+ self.initSession()
+ if encrytion:
+ self.encryptSession()
+ self.startSession()
+ self.paused = False
+ db = DownloadDB()
+ ContentList = self.getContentList()
+ if contentId != None: contentId = int(contentId)
+ if len(ContentList) == 1 or contentId not in [None, -1]:
+ if not contentId: contentId = 0
+ title = os.path.basename(ContentList[contentId]['title'])
+ path = os.path.join(self.storageDirectory, ContentList[contentId]['title'])
+ type = 'file'
+ else:
+ contentId = -1
+ title = ContentList[0]['title'].split('\\')[0]
+ path = os.path.join(self.storageDirectory, title)
+ type = 'folder'
+
+ add = db.add(title, path, type, {'progress': 0}, 'downloading', self.torrentFile, contentId,
+ self.storageDirectory)
+ get = db.get(title)
+ if add or get[5] == 'stopped':
+ if get[5] == 'stopped':
+ db.update_status(get[0], 'downloading')
+ if contentId not in [None, -1]:
+ self.continueSession(int(contentId), Offset=0, seeding=False)
+ else:
+ for i in range(self.torrentFileInfo.num_pieces()):
+ self.torrentHandle.piece_priority(i, 6)
+ thread.start_new_thread(self.downloadLoop, (title,))
+
+ def downloadLoop(self, title):
+ db = DownloadDB()
+ status = 'downloading'
+ while db.get(title) and status != 'stopped':
+ xbmc.sleep(3000)
+ status = db.get_status(title)
+ if not self.paused:
+ if status == 'pause':
+ self.paused = True
+ self.session.pause()
+ else:
+ if status != 'pause':
+ self.paused = False
+ self.session.resume()
+ s = self.torrentHandle.status()
+ info = {}
+ info['upload'] = s.upload_payload_rate
+ info['download'] = s.download_payload_rate
+ info['peers'] = s.num_peers
+ info['seeds'] = s.num_seeds
+ iterator = int(s.progress * 100)
+ info['progress'] = iterator
+ db.update(title, info)
+ self.debug()
+ self.session.remove_torrent(self.torrentHandle)
+ return
+
+ def initSession(self):
+ self.session = self.lt.session()
+ self.session.set_alert_mask(self.lt.alert.category_t.error_notification | self.lt.alert.category_t.status_notification | self.lt.alert.category_t.storage_notification)
+ #self.session.set_alert_mask(self.lt.alert.category_t.all_categories)
+ self.session.add_dht_router("router.bittorrent.com", 6881)
+ self.session.add_dht_router("router.utorrent.com", 6881)
+ self.session.start_dht()
+ self.session.start_lsd()
+ self.session.start_upnp()
+ self.session.start_natpmp()
+ try:
+ port = int(self.__settings__.getSetting('listen_port'))
+ self.session.listen_on(port, port+10)
+ except:
+ try:
+ log('listen_on(%d, %d) error' %(port, port+10))
+ except:
+ log('listen_port %s error' %(self.__settings__.getSetting('listen_port')))
+
+ pc_config = int(self.__settings__.getSetting('pc_config'))
+
+ # Session settings
+ try:
+ session_settings = self.session.get_settings()
+ #
+ session_settings['announce_to_all_tiers'] = True
+ session_settings['announce_to_all_trackers'] = True
+ session_settings['peer_connect_timeout'] = 2
+ session_settings['rate_limit_ip_overhead'] = True
+ session_settings['request_timeout'] = 1
+ session_settings['torrent_connect_boost'] = 50
+ session_settings['user_agent'] = 'uTorrent/2200(24683)'
+ if pc_config == 0:
+ #good pc
+ session_settings['connections_limit'] = 200
+ session_settings['unchoke_slots_limit'] = 10
+ session_settings['connection_speed'] = 200
+ session_settings['file_pool_size'] = 40
+ elif pc_config == 1:
+ #bad pc/router
+ session_settings['connections_limit'] = 100
+ session_settings['half_open_limit'] = (lambda: windows_check() and
+ (lambda: vista_check() and 4 or 8)() or 50)()
+ session_settings['unchoke_slots_limit'] = 4
+ session_settings['connection_speed'] = 100
+ session_settings['file_pool_size'] = 40
+
+ #session_settings['cache_size'] = 0
+ #session_settings['use_read_cache'] = False
+
+ except:
+ #0.15 compatibility
+ log('[initSession]: Session settings 0.15 compatibility')
+ session_settings = self.session.settings()
+
+ session_settings.announce_to_all_tiers = True
+ session_settings.announce_to_all_trackers = True
+ session_settings.connection_speed = 100
+ session_settings.peer_connect_timeout = 2
+ session_settings.rate_limit_ip_overhead = True
+ session_settings.request_timeout = 1
+ session_settings.torrent_connect_boost = 100
+ session_settings.user_agent = 'uTorrent/2200(24683)'
+ #
+ self.session.set_settings(session_settings)
+
+ def encryptSession(self):
+ # Encryption settings
+ log('Encryption enabling...')
+ try:
+ encryption_settings = self.lt.pe_settings()
+ encryption_settings.out_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced)
+ encryption_settings.in_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced)
+ encryption_settings.allowed_enc_level = self.lt.enc_level.both
+ encryption_settings.prefer_rc4 = True
+ self.session.set_pe_settings(encryption_settings)
+ log('Encryption on!')
+ except Exception, e:
+ log('Encryption failed! Exception: ' + str(e))
+ pass
+
+ def startSession(self):
+ if self.magnetLink:
+ self.torrentFileInfo = self.getMagnetInfo()
+ torrent_info={'ti': self.torrentFileInfo,
+ 'save_path': self.storageDirectory,
+ 'flags': 0x300,
+ #'storage_mode': self.lt.storage_mode_t(1),
+ 'paused': False,
+ #'auto_managed': False,
+ #'duplicate_is_error': True
+ }
+ if self.save_resume_data:
+ log('loading resume data')
+ torrent_info['resume_data']=self.save_resume_data
+ else:
+ resume_file=self.resume_data_path()
+ if xbmcvfs.exists(resume_file):
+ log('loading resume data from file '+resume_file)
+ try:
+ resumDataFile=xbmcvfs.File(resume_file,'rb')
+ self.save_resume_data=resumDataFile.read()
+ resumDataFile.close()
+ torrent_info['resume_data']=self.save_resume_data
+
+ except:
+ log('Failed to load resume data from file '+ resume_file)
+ self.torrentHandle = self.session.add_torrent(torrent_info)
+ self.torrentHandle.set_sequential_download(True)
+ self.torrentHandle.set_max_connections(60)
+ self.torrentHandle.set_max_uploads(-1)
+ self.stopSession()
+
+ def stopSession(self):
+ for i in range(self.torrentFileInfo.num_pieces()):
+ self.torrentHandle.piece_priority(i, 0)
+
+ def continueSession(self, contentId=0, Offset=0, seeding=False, isMP4=False):
+ self.piece_length = self.torrentFileInfo.piece_length()
+ selectedFileInfo = self.getContentList()[contentId]
+ if not Offset:
+ Offset = selectedFileInfo['size'] / (1024 * 1024)
+ self.partOffset = (Offset * 1024 * 1024 / self.piece_length) + 1
+ self.startPart = selectedFileInfo['offset'] / self.piece_length
+ self.endPart = int((selectedFileInfo['offset'] + selectedFileInfo['size']) / self.piece_length)
+ multiplier = self.partOffset / 5
+ log('continueSession: multiplier ' + str(multiplier))
+ for i in range(self.startPart, self.startPart + self.partOffset):
+ if i <= self.endPart:
+ self.torrentHandle.piece_priority(i, 7)
+ if isMP4 and i % multiplier == 0:
+ self.torrentHandle.piece_priority(self.endPart - i / multiplier, 7)
+ if multiplier >= i:
+ self.torrentHandle.piece_priority(self.endPart - i, 7)
+
+ def checkThread(self):
+ if self.threadComplete == True:
+ self.resume_data()
+ log('checkThread KIIIIIIIIIIILLLLLLLLLLLLLLL')
+ try:
+ self.session.remove_torrent(self.torrentHandle)
+ except:
+ log('RuntimeError: invalid torrent handle used')
+ self.session.stop_natpmp()
+ self.session.stop_upnp()
+ self.session.stop_lsd()
+ self.session.stop_dht()
+
+ def resume_data(self):
+ wasPaused=self.session.is_paused()
+ self.session.pause()
+ self.save_resume_data=None
+
+ try:
+ if not self.torrentHandle.is_valid():
+ return
+ status = self.torrentHandle.status()
+ if not status.has_metadata:
+ return
+ if not status.need_save_resume:
+ return
+
+ log('[save_resume_data]: waiting for alert...')
+ self.torrentHandle.save_resume_data(self.lt.save_resume_flags_t.flush_disk_cache)
+ received=False
+ while not received:
+ self.session.wait_for_alert(1000)
+ a = self.session.pop_alert()
+ log('[save_resume_data]: ['+str(type(a))+'] the alert '+str(a)+' is received')
+ if type(a) == self.lt.save_resume_data_alert:
+ received = True
+ debug('[save_resume_data]: '+str(dir(a)))
+ self.save_resume_data=self.lt.bencode(a.resume_data)
+ log('[save_resume_data]: the torrent resume data are received')
+ try:
+ resumeFileHandler = xbmcvfs.File(self.resume_data_path(), "w+b")
+ resumeFileHandler.write(self.save_resume_data)
+ resumeFileHandler.close()
+ log('[save_resume_data]: the torrent resume data to file' + self.resume_data_path())
+ except:
+ log('[save_resume_data]: failed to save the torrent resume data to file')
+ elif type(a) == self.lt.save_resume_data_failed_alert:
+ received = True
+ log('[save_resume_data]: save_resume_data() failed')
+ log('[save_resume_data]: done.')
+
+ finally:
+ if not wasPaused:
+ self.session.resume()
+
+ def debug(self):
+ #try:
+ if 1==1:
+ # log(str(self.getFilePath(0)))
+ s = self.torrentHandle.status()
+ #get_cache_status=self.session.get_cache_status()
+ #log('get_cache_status - %s/%s' % (str(get_cache_status.blocks_written), str(get_cache_status.blocks_read)))
+ # get_settings=self.torrentHandle.status
+ # log(s.num_pieces)
+ #priorities = self.torrentHandle.piece_priorities()
+ #log(str(priorities))
+
+ state_str = ['queued', 'checking', 'downloading metadata',
+ 'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
+ log('[%s] %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \
+ (self.lt.version, s.progress * 100, s.download_rate / 1000,
+ s.upload_rate / 1000, s.num_peers, state_str[s.state]))
+ #log('%s %s' % (self.get_debug_info('dht_state'), self.get_debug_info('trackers_sum')))
+ #debug('TRACKERS:' +str(self.torrentHandle.trackers()))
+
+ #received=self.session.pop_alert()
+ #while received:
+ # debug('[debug]: ['+str(type(received))+'] the alert '+str(received)+' is received')
+ # #if type(received) == self.lt.torrent_finished_alert:
+ # # self.session.pause()
+ # received = self.session.pop_alert()
+
+ #log('is_dht_running:' +str(self.session.is_dht_running()))
+ #log('dht_state:' +str(self.session.dht_state()))
+ #i = 0
+ # for t in s.pieces:
+ # if t: i=i+1
+ #log(str(self.session.pop_alert())
+ # log(str(s.pieces[self.startPart:self.endPart]))
+ # log('True pieces: %d' % i)
+ # log(s.current_tracker)
+ # log(str(s.pieces))
+ #except:
+ else:
+ log('debug error')
+ pass
+
+ def get_debug_info(self, info):
+ result=''
+ if info in ['trackers_full','trackers_sum']:
+ trackers=[]
+ for tracker in self.torrentHandle.trackers():
+ trackers.append((tracker['url'], tracker['fails'], tracker['verified']))
+ if info=='trackers_full':
+ for url, fails, verified in trackers:
+ result=result+'%s: f=%d, v=%s' %(url, fails, str(verified))
+ if info=='trackers_sum':
+ fails_sum, verified_sum = 0, 0
+ for url, fails, verified in trackers:
+ fails_sum+=fails
+ if verified: verified_sum+=1
+ result=result+'Trackers: verified %d/%d, fails=%d' %(verified_sum, len(trackers)-1, fails_sum)
+ if info=='dht_state':
+ is_dht_running='ON' if self.session.is_dht_running() else 'OFF'
+ try:
+ nodes=self.session.dht_state().get('nodes')
+ except:
+ nodes=None
+ nodes=len(nodes) if nodes else 0
+ result='DHT: %s (%d)' % (is_dht_running, nodes)
+ return result
+
+ def dump(self, obj):
+ for attr in dir(obj):
+ try:
+ log("'%s':'%s'," % (attr, getattr(obj, attr)))
+ except:
+ pass
+
+ def resume_data_path(self):
+ path=self.torrentFile + ".resume_data"
+ return path