diff --git a/.idea/workspace.xml b/.idea/workspace.xml index f1cbe6c..0ed5017 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,7 +1,23 @@ - + + + + + + + + + + + + + + + + + @@ -33,61 +49,69 @@ - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -96,8 +120,8 @@ - - + + @@ -107,17 +131,17 @@ - + - + - - + + @@ -130,164 +154,174 @@ - - + + - - + + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -305,18 +339,24 @@ @@ -352,6 +392,7 @@ + @@ -384,60 +425,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -662,27 +658,27 @@ - - + + - - + - + - + - + + - + @@ -713,239 +709,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -990,7 +753,6 @@ - @@ -1007,126 +769,124 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1135,7 +895,6 @@ - @@ -1145,44 +904,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -1233,44 +978,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -1321,44 +1052,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -1393,50 +1110,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1444,14 +1117,6 @@ - - - - - - - - @@ -1463,23 +1128,6 @@ - - - - - - - - - - - - - - - - - @@ -1495,187 +1143,320 @@ + + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.py b/Content.py index 258a632..b8f100a 100644 --- a/Content.py +++ b/Content.py @@ -230,4 +230,14 @@ class Content: else: return 'Empty string' - #print str(Content().has_category('x')) \ No newline at end of file + def sizeConvert(self, sizeBytes): + if long(sizeBytes) >= 1024 * 1024 * 1024: + size = str(long(sizeBytes) / (1024 * 1024 * 1024)) + 'GB' + elif long(sizeBytes) >= 1024 * 1024: + size = str(long(sizeBytes) / (1024 * 1024)) + 'MB' + elif sizeBytes >= 1024: + size = str(long(sizeBytes) / 1024) + 'KB' + else: + size = str(long(sizeBytes)) + 'B' + + return size \ No newline at end of file diff --git a/Core.py b/Core.py index a69b8e3..69c0772 100644 --- a/Core.py +++ b/Core.py @@ -63,7 +63,6 @@ class Core: ('«', '"'), ('»', '"'), ) - HistoryDB_name, HistoryDB_ver = 'history', 1.1 scrapperDB_ver = {'en':'1.0', 'ru':'1.2'} print 'SYS ARGV: ' + str(sys.argv) @@ -88,23 +87,31 @@ class Core: else: self.__settings__.setSetting('delete_russian', 'false') self.__settings__.setSetting('plugin_name',self.__plugin__) + ListString = 'XBMC.RunPlugin(%s)' % (sys.argv[0] + '?action=%s&action2=%s&%s=%s') + contextMenu = [(self.localize('Search Control Window'), + 'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))] + if self.history_bool: - contextMenu = [(self.localize('Search Control Window'), - 'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))] - contextMenu.append( - (self.localize('Clear Search History'), ListString % ('History', 'clear', 'addtime', ''))) + HistorycontextMenu=[] + HistorycontextMenu.extend(contextMenu) + HistorycontextMenu.append( + (self.localize('Clear %s') % self.localize('Search History'), ListString % ('History', 'clear', 'addtime', ''))) self.drawItem('< %s >' % self.localize('Search History'), 'History', - image=self.ROOT + '/icons/history2.png', contextMenu=contextMenu, replaceMenu=False) + image=self.ROOT + '/icons/history2.png', contextMenu=HistorycontextMenu, replaceMenu=False) self.drawItem('< %s >' % self.localize('Search'), 'search', image=self.ROOT + '/icons/search.png', ) - contextMenu = [ - (self.localize('Search Control Window'), 'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))] - contextMenu.append((self.localize('Reset All Cache DBs'), + CLcontextMenu=[] + CLcontextMenu.extend(contextMenu) + CLcontextMenu.append((self.localize('Reset All Cache DBs'), ListString % ('full_download', '', 'url', json.dumps({'action': 'delete'})))) self.drawItem('< %s >' % self.localize('Content Lists'), 'openContent', image=self.ROOT + '/icons/media.png', - contextMenu=contextMenu, replaceMenu=False) - self.drawItem('< %s >' % self.localize('Personal List'), 'List', image=self.ROOT + '/icons/list.png', - contextMenu=contextMenu, replaceMenu=False) + contextMenu=CLcontextMenu, replaceMenu=False) + DLScontextMenu=[] + DLScontextMenu.extend(contextMenu) + DLScontextMenu.append( + (self.localize('Clear %s') % self.localize('Download Status'), ListString % ('DownloadStatus', 'clear', 'addtime', ''))) + self.drawItem('< %s >' % self.localize('Download Status'), 'DownloadStatus', image=self.ROOT + '/icons/download.png', + contextMenu=DLScontextMenu, replaceMenu=False) self.drawItem('< %s >' % self.localize('Torrent-client Browser'), 'uTorrentBrowser', image=self.ROOT + '/icons/torrent-client.png') self.drawItem('< %s >' % self.localize('.torrent Player'), 'torrentPlayer', @@ -262,13 +269,78 @@ class Core: lockView('wide') def test(self, params={}): - #xbmc.executebuiltin('XBMC.ActivateWindow(%s)' % 'Videos,plugin://plugin.video.torrenter/?' - # 'action=torrentPlayer&url=D%3A%5Ctest.torrent') - #self.test_scrapper() - thread.exit() + #db=DownloadDB() + #db.add(u'XXX2', 'file', json.dumps({'seeds':1,'leechers':1}), 20) + #url='magnet:?xt=urn:btih:MZLDDZU5MWZWICIGQN6YDVAXJNNISU5W&dn=Jimmy.Fallon.2015.01.09.Don.Cheadle.HDTV.x264-CROOKS&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.publicbt.com:80&tr=udp://tracker.istole.it:80&tr=udp://open.demonii.com:80&tr=udp://tracker.coppersurfer.tk:80' + #filename='D:\\torrents\\Torrenter\\torrents\\Jimmy.Fallon.2015.01.09.Don.Cheadle.HDTV.x264-CROOKS.mp4.torrent' + #torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory) + #self.__settings__.setSetting("lastTorrent", torrent.saveTorrent(filename)) + #torrent.downloadProcess() + self.DownloadStatus() + + def DownloadStatus(self, params={}): + db = DownloadDB() + get = params.get + action2 = get('action2') + type = get('type') + path = get('path') + addtime = get('addtime') + + if action2 == 'notfinished': + showMessage(self.localize('Download Status'), self.localize('Download has not finished yet')) + + if action2 == 'play': + if type=='file': + xbmc.Player().play(urllib.unquote_plus(path)) + else: + path=urllib.unquote_plus(path) + dirs, files=xbmcvfs.listdir(path+os.sep) + if len(dirs)>0: + for dir in dirs: + link={'action2':'play', 'type':'folder', 'path':os.path.join(path,dir)} + self.drawItem(dir, 'DownloadStatus', link, image='', isFolder=True) + for file in files: + link={'action2':'play', 'type':'file', 'path':os.path.join(path,file)} + self.drawItem(file, 'DownloadStatus', link, image='', isFolder=False) + view_style('DownloadStatus') + xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) + return + + if action2 == 'delete': + db.delete(addtime) + xbmc.executebuiltin('Container.Refresh') + showMessage(self.localize('Download Status'), self.localize('Deleted! It will not stop download')) + + if action2 == 'clear': + db.clear() + showMessage(self.localize('Download Status'), self.localize('Clear!')) + + if not action2: + items = db.get_all() + if items: + ListString = 'XBMC.RunPlugin(%s)' % (sys.argv[0] + '?action=DownloadStatus&action2=%s&%s=%s') + for addtime, title, path, type, info in items: + jsoninfo=json.loads(urllib.unquote_plus(info)) + progress=int(jsoninfo.get('progress')) + title = '[%d%%] %s' % (progress, title) + if progress<100: + if jsoninfo.get('seeds')!=None and jsoninfo.get('peers')!=None and \ + jsoninfo.get('download')!=None and jsoninfo.get('upload')!=None: + d,u=int(jsoninfo['download']/ 1000000), int(jsoninfo['upload'] / 1000000) + s,p=str(jsoninfo['seeds']),str(jsoninfo['peers']) + title='%s [S/L %s/%s][D/U %s/%s (MB/s)]' %(title,s,p,d,u) + link={'action2':'notfinished'} + contextMenu=[((self.localize('Delete from %s') % self.localize('Download Status'), ListString % ('delete', 'addtime', str(addtime))))] + self.drawItem(title, 'DownloadStatus', link, image='', contextMenu=contextMenu, replaceMenu=True) + else: + contextMenu=[((self.localize('Delete from %s') % self.localize('Download Status'), ListString % ('delete', 'addtime', str(addtime))))] + link={'action2':'play', 'type':type, 'path':path.encode('utf-8')} + self.drawItem('[B]%s[/B]' % title, 'DownloadStatus', link, image='', contextMenu=contextMenu, replaceMenu=False, isFolder=type=='folder') + view_style('DownloadStatus') + xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) def History(self, params={}): - db = HistoryDB(self.HistoryDB_name, self.HistoryDB_ver) + db = HistoryDB() get = params.get action2 = get('action2') url = get('url') @@ -366,6 +438,7 @@ class Core: def drawContent(self, category_dict, provider=None, category=None, subcategory=None): if not category and not provider: + self.drawItem('[COLOR FFFFFFFF][B]< %s >[/B][/COLOR]' % self.localize('Personal List'), 'List', image=self.ROOT + '/icons/list.png') for cat in category_dict.keys(): cat_con = category_dict[cat] if isinstance(cat_con, dict): @@ -744,9 +817,12 @@ class Core: link = {'url': '%s::%s' % (provider, urllib.quote_plus(label)), 'thumbnail': img} contextMenu = [ - (self.localize('Download'), + (self.localize('Download via T-client'), 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( - sys.argv[0], 'downloadFilesList', urllib.quote_plus('%s::%s' % (provider, info.get('link'))))) + sys.argv[0], 'downloadFilesList', urllib.quote_plus('%s::%s' % (provider, info.get('link'))))), + (self.localize('Download via Libtorrent'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( + sys.argv[0], 'downloadLibtorrent', urllib.quote_plus('%s::%s' % (provider, info.get('link'))))) ] self.drawItem(title, 'openTorrent', link, img, info=info, contextMenu=contextMenu, replaceMenu=False) @@ -787,8 +863,13 @@ class Core: '%s S%2dE%2d' % (get('original_title'), int(get('season')), int(get('episode')))) for title in options: - link = {'url': title.encode('utf-8', 'ignore'), 'thumbnail': img, 'save_folder':save_folder.encode('utf-8', 'ignore')} - self.drawItem(title.encode('utf-8', 'ignore'), 'search', link, img) + try: + title=title.encode('utf-8') + save_folder=save_folder.encode('utf-8') + except: pass + link = {'url': title, 'thumbnail': img, 'save_folder':save_folder} + #print str(link) + self.drawItem(title, 'search', link, img) view_style('searchOption') xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) @@ -800,7 +881,8 @@ class Core: if isinstance(link, dict): link_url = '' for key in link.keys(): - link_url = '%s&%s=%s' % (link_url, key, urllib.quote_plus(str(link.get(key)))) + if link.get(key): + link_url = '%s&%s=%s' % (link_url, key, urllib.quote_plus(link.get(key))) url = '%s?action=%s' % (sys.argv[0], action) + link_url else: url = '%s?action=%s&url=%s' % (sys.argv[0], action, urllib.quote_plus(link)) @@ -1053,17 +1135,20 @@ class Core: pass for title, identifier in contentListNew: - contextMenu = [(self.localize('Download'), - 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( - sys.argv[0], 'downloadopenTorrent', str(identifier))) + contextMenu = [ + (self.localize('Download via T-client'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&ind=%s') % ( + sys.argv[0], 'downloadFilesList', str(identifier))), + (self.localize('Download via Libtorrent'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&ind=%s') % ( + sys.argv[0], 'downloadLibtorrent', str(identifier))), ] self.drawItem(title, 'playTorrent', identifier, isFolder=False, action2=ids_video.rstrip(','), contextMenu=contextMenu, replaceMenu=False) view_style('torrentPlayer') xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) - def playTorrent(self, params={}): - torrentUrl = self.__settings__.getSetting("lastTorrent") + def userStorage(self, params): if self.__settings__.getSetting("keep_files")=='true' \ and self.__settings__.getSetting("ask_dir")=='true': try: @@ -1081,6 +1166,10 @@ class Core: return if len(dirname)>0: self.userStorageDirectory=dirname + + def playTorrent(self, params={}): + torrentUrl = self.__settings__.getSetting("lastTorrent") + self.userStorage(params) if self.torrent_player == '0': if 0 != len(torrentUrl): self.Player = TorrentPlayer(userStorageDirectory=self.userStorageDirectory, torrentUrl=torrentUrl, params=params) @@ -1229,9 +1318,12 @@ class Core: for title, identifier in contentListNew: contextMenu = [ - (self.localize('Download'), - 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( - sys.argv[0], 'downloadopenTorrent', str(identifier))) + (self.localize('Download via T-client'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&ind=%s') % ( + sys.argv[0], 'downloadFilesList', str(identifier))), + (self.localize('Download via Libtorrent'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&ind=%s') % ( + sys.argv[0], 'downloadLibtorrent', str(identifier))), ] link = {'url': identifier, 'thumbnail': thumbnail, 'save_folder':save_folder} self.drawItem(title, 'playTorrent', link, image=thumbnail, isFolder=False, @@ -1239,16 +1331,12 @@ class Core: view_style('openTorrent') xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) - def downloadopenTorrent(self, params={}): - url = self.__settings__.getSetting("lastTorrent") - self.downloadFilesList({'url': url, 'ind': params.get("url")}) - def openSection(self, params={}): get = params.get url = urllib.unquote_plus(get("url")) addtime=get("addtime") if not addtime and self.__settings__.getSetting('history')=='true': - HistoryDB(self.HistoryDB_name, self.HistoryDB_ver).add(url) + HistoryDB().add(url) try: external = urllib.unquote_plus(get("external")) except: @@ -1261,7 +1349,7 @@ class Core: searchersList = [] if not external or external == 'torrenterall': if addtime: - providers=HistoryDB(self.HistoryDB_name, self.HistoryDB_ver).get_providers(addtime) + providers=HistoryDB().get_providers(addtime) if providers: for searcher in providers: searchersList.append(searcher + '.py') @@ -1360,9 +1448,12 @@ class Core: else: for (order, seeds, leechers, size, title, link, image) in filesList: contextMenu = [ - (self.localize('Download'), + (self.localize('Download via T-client'), 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( - sys.argv[0], 'downloadFilesList', urllib.quote_plus(link))) + sys.argv[0], 'downloadFilesList', urllib.quote_plus(link))), + (self.localize('Download via Libtorrent'), + 'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % ( + sys.argv[0], 'downloadLibtorrent', urllib.quote_plus(link))) ] title = self.titleMake(seeds, leechers, size, title) link = {'url': link, 'thumbnail': thumbnail, 'save_folder':save_folder} @@ -1404,7 +1495,10 @@ class Core: dirname = self.__settings__.getSetting("torrent_dir") get = params.get - url = urllib.unquote_plus(get("url")) + try: + url = urllib.unquote_plus(get("url")) + except: + url = self.__settings__.getSetting("lastTorrent").decode('utf-8') ind = get("ind") if not ind: self.__settings__.setSetting("lastTorrentUrl", url) @@ -1442,6 +1536,38 @@ class Core: id = self.chooseHASH()[0] Download().setprio(id, ind) + def downloadLibtorrent(self, params={}): + get = params.get + self.userStorage(params) + try: + url = urllib.unquote_plus(get("url")) + except: + url = self.__settings__.getSetting("lastTorrent").decode('utf-8') + ind = get("ind") + if not ind: + self.__settings__.setSetting("lastTorrentUrl", url) + classMatch = re.search('(\w+)::(.+)', url) + if classMatch: + searcher = classMatch.group(1) + if self.ROOT + os.sep + 'resources' + os.sep + 'searchers' not in sys.path: + sys.path.insert(0, self.ROOT + os.sep + 'resources' + os.sep + 'searchers') + try: + searcherObject = getattr(__import__(searcher), searcher)() + except Exception, e: + print 'Unable to use searcher: ' + searcher + ' at ' + self.__plugin__ + ' openTorrent(). Exception: ' + str(e) + return + url = searcherObject.getTorrentFile(classMatch.group(2)) + torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory) + torrent.initSession() + self.__settings__.setSetting("lastTorrent", torrent.saveTorrent(url)) + if 0 < int(self.__settings__.getSetting("upload_limit")): + torrent.setUploadLimit(int(self.__settings__.getSetting("upload_limit")) * 1000000 / 8) #MBits/second + if 0 < int(self.__settings__.getSetting("download_limit")): + torrent.setDownloadLimit( + int(self.__settings__.getSetting("download_limit")) * 1000000 / 8) #MBits/second + torrent.downloadProcess(ind) + showMessage(self.localize('Download Status'), self.localize('Added!')) + def titleMake(self, seeds, leechers, size, title): #AARRGGBB diff --git a/Downloader.py b/Downloader.py index 30c7384..9f70fe5 100644 --- a/Downloader.py +++ b/Downloader.py @@ -97,8 +97,8 @@ class Torrent(): hasher.update(string.encode('utf-8', 'ignore')) return hasher.hexdigest() - def downloadProcess(self, contentId): - pass + def downloadProcess(self, contentId=None): + return self.player.downloadProcess(contentId) def initSession(self): return self.player.initSession() diff --git a/Libtorrent.py b/Libtorrent.py index 84b82eb..d4b9cbc 100644 --- a/Libtorrent.py +++ b/Libtorrent.py @@ -28,7 +28,7 @@ import sys import platform from StringIO import StringIO import gzip -from functions import file_decode, file_encode, isSubtitle +from functions import file_decode, file_encode, isSubtitle, DownloadDB import xbmc import xbmcgui @@ -248,13 +248,44 @@ class Libtorrent: return hasher.hexdigest() def downloadProcess(self, contentId): - pass - #for part in range(self.startPart, self.endPart + 1): - # print 'getPiece'+str(part) - # self.getPiece(part) - # time.sleep(0.5) - # self.checkThread() - #self.threadComplete = True + self.startSession() + db=DownloadDB() + ContentList=self.getContentList() + if len(ContentList)==1 or contentId: + if not contentId: contentId=0 + title=os.path.basename(ContentList[int(contentId)]['title']) + path=os.path.join(self.storageDirectory, ContentList[int(contentId)]['title']) + type='file' + else: + title=ContentList[0]['title'].split('\\')[0] + path=os.path.join(self.storageDirectory, title) + type='folder' + + add=db.add(title, path, type, {'progress':0}) + if add: + if None!=contentId: + 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): + iterator=0 + db=DownloadDB() + while iterator<100: + xbmc.sleep(1000) + status = self.torrentHandle.status() + info={} + info['upload']=status.upload_payload_rate + info['download']=status.download_payload_rate + info['peers']=status.num_peers + info['seeds']=status.num_seeds + iterator = int(status.progress * 100) + info['progress']=iterator + db.update(title, info) + self.debug() def initSession(self): try: @@ -304,8 +335,8 @@ class Libtorrent: self.torrentHandle.piece_priority(self.endPart, 7) #thread.start_new_thread(self.checkProcess, ()) #thread.start_new_thread(self.downloadProcess, (contentId,)) - if seeding:# and None == self.magnetLink: - thread.start_new_thread(self.addToSeeding, (contentId,)) + #if seeding:# and None == self.magnetLink: + # thread.start_new_thread(self.addToSeeding, (contentId,)) def addToSeeding(self, contentId): print 'addToSeeding!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1' diff --git a/Localization.py b/Localization.py index 4f83673..646a3f7 100644 --- a/Localization.py +++ b/Localization.py @@ -173,7 +173,7 @@ dictionary = { 'Search History': 'История Поиска', 'Favourites': 'Избранное', 'Favourites SH': 'Избранное ИП', - 'Clear Search History': 'Очистить Историю Поиска', + 'Clear %s': 'Очистить %s', 'Clear!': 'Очищено!', 'kb/s': 'Кб/с', 'Queued': 'В очереди', @@ -199,6 +199,11 @@ dictionary = { 'Save to path':'Сохранить в папку', 'Return Russian stuff':'Вернуть русские трекеры', '%d files have been returned':'%d файлов возвращено', + 'Download via T-client':'Скачать Торр-клиентом', + 'Download via Libtorrent':'Скачать Libtorrent\'ом', + 'Download Status':'Статус Загрузки', + 'Download has not finished yet':'Загрука не завершена', + 'Deleted! It will not stop download':'Удалено! Это не остановит загрузку', } } diff --git a/README.txt b/README.txt index e736143..5116477 100644 --- a/README.txt +++ b/README.txt @@ -17,6 +17,7 @@ No installation required, will be downloaded with plugin from repository as modu or you could compile it: sudo apt-get build-dep python-libtorrent +sudo apt-get install subversion svn co https://libtorrent.svn.sourceforge.net/svnroot/libtorrent/trunk/ lt/ cd lt/ ./autotool.sh @@ -42,6 +43,7 @@ ________________________________________________________________________________ или компилируем: sudo apt-get build-dep python-libtorrent +sudo apt-get install subversion svn co https://libtorrent.svn.sourceforge.net/svnroot/libtorrent/trunk/ lt/ cd lt/ ./autotool.sh diff --git a/addon.xml b/addon.xml index a351118..1b0ed29 100644 --- a/addon.xml +++ b/addon.xml @@ -12,12 +12,12 @@ all Plugin helps you to watch videos from p2p torrent-networks, without full predownload. - Plugin helps you to watch videos from p2p torrent-networks, without full predownload (uses inner python-libtorrent) or Ace Stream. It also can add, control torrents and play downloaded files with external uTorrent, Transmisson or Vuse. + Plugin helps you to watch videos from p2p torrent-networks, without full predownload (uses python-libtorrent or Ace Stream). It also can add, control torrents and play downloaded files with external uTorrent, Transmisson or Vuse. GNU GPLv3 http://www.gnu.org/licenses/ Плагин позволяет просматривать видео из пиринговых торрент-сетей, не дожидаясь полного скачивания. - Плагин позволяет просматривать видео из пиринговых торрент-сетей, не дожидаясь полного скачивания. Использует внутренюю библиотеку python-libtorrent или Ace Stream. Так же плагин может добавлять, проигрывать и управлять скачками в uTorrent, Transmisson и Vuse. + Плагин позволяет просматривать видео из пиринговых торрент-сетей, не дожидаясь полного скачивания. Использует библиотеку python-libtorrent или Ace Stream. Так же плагин может добавлять, проигрывать и управлять скачками в uTorrent, Transmisson и Vuse. GNU GPLv3 http://www.gnu.org/licenses/ diff --git a/changelog.txt b/changelog.txt index 84469fb..0cf11f6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,8 @@ -[B]Version 2.0.8[/B] +[B]Version 2.0.9[/B] +[+] Загрузка: Добавлена возможность загружать торренты в фоне +[+] Списки Медиа: Добавлен KickAssSo + +[B]Version 2.0.8[/B] [+] Проигрывание: Добавлена возможность менять путь хранения [+] Торрент-клиент: Добавлена возможность менять путь скачки diff --git a/controlcenter.py b/controlcenter.py index 380a6d3..e6d73c0 100644 --- a/controlcenter.py +++ b/controlcenter.py @@ -13,7 +13,6 @@ __language__ = __settings__.getLocalizedString __version__ = __settings__.getAddonInfo('version') __plugin__ = __settings__.getAddonInfo('name') + " v." + __version__ __root__ = __settings__.getAddonInfo('path') -HistoryDB_name, HistoryDB_ver = 'history', 1.1 print 'SYS ARGV: ' + str(sys.argv) @@ -176,7 +175,7 @@ class ControlCenter(AddonDialogWindow): self.keys = self.dic.keys() if addtime: self.addtime=addtime - self.db = HistoryDB(HistoryDB_name, HistoryDB_ver) + self.db = HistoryDB() providers = self.db.get_providers(addtime) if not providers: self.db.set_providers(addtime, self.dic) @@ -364,7 +363,7 @@ class ControlCenter(AddonDialogWindow): def main(): - title='Global Torrenter Control Center' + title='Torrenter Global Control Center' addtime=None if params.get('title'): title=str(params.get('title')) diff --git a/functions.py b/functions.py index ed7a7a5..41698b3 100644 --- a/functions.py +++ b/functions.py @@ -54,6 +54,7 @@ def clearStorage(userStorageDirectory): shutil.rmtree(userStorageDirectory, ignore_errors=True) xbmcvfs.mkdir(userStorageDirectory) shutil.move(os.path.join(temp, 'torrents'), os.path.join(userStorageDirectory, 'torrents')) + DownloadDB().clear() showMessage(Localization.localize('Storage'), Localization.localize('Storage was cleared'), forced=True) @@ -259,224 +260,6 @@ def calculate(full): return repl_const - -def auto_scan(): - from torrents import ScanAll - - scan = CacheDB('autoscan') - if not scan.get(): scan.add() - try: - if scan.get() \ - and int(time.time()) - scan.get() > refresh_period * 3600: - scan.delete() - scan.add() - ScanAll() - except: - showMessage(__language__(30279), __language__(30277)) - - -def DownloadCache(): - useTVDB = getSettingAsBool('tvdb') - urls = [__baseurl__ + '/profile/shows/', - __baseurl__ + '/profile/episodes/next/', - __baseurl__ + '/profile/episodes/unwatched/', - __baseurl__ + '/shows/top/all/', - __baseurl__ + '/shows/top/male/', - __baseurl__ + '/shows/top/female/', ] - titles = [] - lang = [30100, 30107, 30106, 30108, 30109, 30110] - for l in lang: titles.append(__language__(l)) - - data = Data(cookie_auth, __baseurl__ + '/profile/shows/').get() - if data: - jdata = json.loads(data) - count = len(jdata) - - dialog = xbmcgui.Dialog() - ok = dialog.yesno(__language__(30548), __language__(30517) % count, __language__(30518)) - if ok: - for showId in jdata: - if ruName == 'true' and jdata[showId]['ruTitle']: - title = jdata[showId]['ruTitle'].encode('utf-8') - else: - title = jdata[showId]['title'] - titles.append(title) - urls.append(__baseurl__ + '/shows/' + showId) - titles.append(title) - urls.append(__baseurl__ + '/profile/shows/' + showId + '/') - - if useTVDB: - from search.scrapers import Scrapers - - TVDB = Scrapers() - - full_count = len(urls) - progressBar = xbmcgui.DialogProgress() - progressBar.create(__language__(30548), __language__(30518)) - for i in range(0, len(urls)): - dat = Data(cookie_auth, urls[i]).get() - if useTVDB: - match = re.compile(__baseurl__ + '/shows/(\d{1,20}?$)').findall(urls[i]) - if match: - jdat = json.loads(dat) - TVDB.scraper('tvdb', {'label': titles[i], 'search': [jdat['title'], titles[i]], - 'year': str(jdat['year'])}) - iterator = int(round(i * 100 / full_count)) - progressBar.update(iterator, __language__(30549) % (i, full_count), titles[i]) - if progressBar.iscanceled(): - progressBar.update(0) - progressBar.close() - break - return - - -class Data(): - def __init__(self, cookie_auth, url, refresh_url=None): - if not xbmcvfs.exists(__tmppath__): - xbmcvfs.mkdirs(__tmppath__) - self.cookie = cookie_auth - self.filename = self.url2filename(url) - self.refresh = False - if refresh_url: - CacheDB(unicode(refresh_url)).delete() - if re.search('profile', refresh_url): - CacheDB(unicode(__baseurl__ + '/profile/episodes/unwatched/')).delete() - self.url = url - self.cache = CacheDB(self.url) - if self.filename: - if not xbmcvfs.exists(self.filename) \ - or getSettingAsBool('forced_refresh_data') \ - or not self.cache.get() \ - or int(time.time()) - self.cache.get() > refresh_period * 3600 \ - or str(refresh_always) == 'true': - self.refresh = True - __settings__.setSetting("forced_refresh_data", "false") - - def get(self, force_cache=False): - if self.filename: - if self.refresh == True and force_cache == False or not xbmcvfs.File(self.filename, - 'r').size() or not re.search( - '=' + __settings__.getSetting("username") + ';', cookie_auth): - self.write() - self.fg = xbmcvfs.File(self.filename, 'r') - try: - self.data = self.fg.read() - except: - self.fg.close() - self.fg = open(self.filename, 'r') - self.data = self.fg.read() - self.fg.close() - x = re.match('.*?}$', self.data) - if not x: self.data = self.data[0:len(self.data) - 1] - return self.data - else: - return get_url(self.cookie, self.url) - - def write(self): - if self.cache.get(): self.cache.delete() - self.data = get_url(self.cookie, self.url) - if self.data: - try: - self.fw = xbmcvfs.File(self.filename, 'w') - except: - self.fw = open(self.filename, 'w') - self.fw.write(self.data) - self.fw.close() - self.cache.add() - elif self.data == False: - Debug('[Data][write] Going offline cuz no self.data ' + str(self.data) + ' self.filename ' + self.filename) - TimeOut().go_offline() - - def url2filename(self, url): - self.files = [r'shows.txt', r'showId_%s.txt', r'watched_showId_%s.txt', r'action_%s.txt', r'top_%s.txt'] - self.urls = [__baseurl__ + '/profile/shows/$', __baseurl__ + '/shows/(\d{1,20}?$)', - __baseurl__ + '/profile/shows/(\d{1,20}?)/$', __baseurl__ + '/profile/episodes/(unwatched|next)/', - __baseurl__ + '/shows/top/(all|male|female)/'] - self.i = -1 - for file in self.urls: - self.i = self.i + 1 - self.match = re.compile(str(file)).findall(url) - if self.match: - self.var = str(self.match[0]) - if str(self.files[self.i]).endswith('%s.txt'): - return os.path.join(__tmppath__, self.files[self.i] % (self.var)) - else: - return os.path.join(__tmppath__, self.files[self.i]) - return None - - -def friend_xbmc(): - login = __settings__.getSetting("username").decode('utf-8', 'ignore') - filename = os.path.join(__tmppath__, '%s.txt' % (login)) - if xbmcvfs.File(filename, 'r').size(): - return True - socket.setdefaulttimeout(3) - scan = CacheDB(login) - if scan.get() and int(time.time()) - scan.get() > refresh_period * 3600 or not scan.get(): - scan.delete() - scan.add() - url = 'http://myshows.me/xbmchub' - ok = Data(cookie_auth, url, '').get() - try: - token = re.compile('').findall(ok)[-1] - post = '{"jsonrpc":"2.0","method":"ToggleFriendship","id":1,"params":{"userId":274684,"add":1,"__token":"' + token + '"}}' - Debug('[friend_xbmc]: token is %s' % (token)) - ok = post_url_json(cookie_auth, __rpcurl__, post) - if ok or not ok: - try: - fw = xbmcvfs.File(filename, 'w') - except: - fw = open(filename, 'w') - fw.write(str(ok)) - fw.close() - return True - else: - return False - except: - Debug('[friend_xbmc] Something went wrong!') - return False - - -def ontop(action='get', ontop=None): - from torrents import prefix - - if action in ('update'): - if ontop: - jdata = json.loads(Data(cookie_auth, __baseurl__ + '/profile/shows/').get()) - jstringdata = json.loads(ontop) - showId = str(jstringdata['showId']) - pre = prefix(showId=int(showId), seasonId=jstringdata['seasonId']) - # if ruName=='true' and jdata[showId]['ruTitle']: title=pre+jdata[showId]['ruTitle'] - # else: - title = pre + jdata[showId]['title'] - if jstringdata['seasonId']: - mode = "25" - title += ' Season ' + str(jstringdata['seasonId']) - else: - mode = "20" - ontop = {'title': title, 'mode': mode, 'argv': {'stringdata': ontop}} - #print unicode(ontop) - __settings__.setSetting("ontop", str(ontop).encode('utf-8')) - elif action == 'get': - x = __settings__.getSetting("ontop") - if x != "None" and x: - y = {} - y['mode'] = re.compile("'%s': '(\d+)'" % ('mode')).findall(x)[0] - y['argv'] = {} - y['argv']['stringdata'] = re.compile("{'%s': '(.+?)'}" % ('stringdata')).findall(x)[0] - y['argv']['showId'] = re.compile('"%s": (\d+),' % ('showId')).findall(y['argv']['stringdata'])[0] - try: - y['argv']['seasonNumber'] = re.compile('"%s": (\d+),' % ('seasonId')).findall(y['argv']['stringdata'])[ - 0] - except: - pass - y['title'] = re.compile("'%s': u'(.+?)'" % ('title')).findall(x)[0].encode('utf-8') - # print unicode(y) - return y - else: - return None - - def getDirList(path, newl=None): l = [] try: @@ -730,7 +513,7 @@ def view_style(func): styles['List'] = styles['drawcontentList'] = 'info3' if view_style == 1: - styles['uTorrentBrowser'] = styles['torrentPlayer'] = styles['openTorrent'] = styles['History'] = 'wide' + styles['uTorrentBrowser'] = styles['torrentPlayer'] = styles['openTorrent'] = styles['History'] = styles['DownloadStatus'] = 'wide' styles['sectionMenu'] = 'icons' if view_style in [1, 3, 4]: @@ -1118,8 +901,8 @@ class ListDB: class HistoryDB: - def __init__(self, name, version=1.0): - self.name = name + '.db3' + def __init__(self, version=1.1): + self.name = 'history.db3' self.version = version def get_all(self): @@ -1637,4 +1420,110 @@ def delete_russian(ok=False, action='delete'): return i return True else: - return False \ No newline at end of file + return False + +class DownloadDB: + def __init__(self, version=1.1): + self.name = 'download.db3' + self.version = version + + def get_all(self): + self._connect() + self.cur.execute('select addtime, title, path, type, jsoninfo from downloads order by addtime DESC') + x = self.cur.fetchall() + self._close() + return x if x else None + + def get(self, title): + self._connect() + self.cur.execute('select addtime from downloads where title="' + title + '"') + x = self.cur.fetchone() + self._close() + return x[0] if x else None + + def add(self, title, path, type, info): + try: + title = title.decode('utf-8') + except: + pass + try: + path = path.decode('utf-8') + except: + pass + if not self.get(title): + self._connect() + self.cur.execute('insert into downloads(addtime, title, path, type, jsoninfo)' + ' values(?,?,?,?,?)', (int(time.time()), title, path, type, json.dumps(info))) + self.db.commit() + self._close() + return True + else: + return False + + def update(self, title, info={}): + try: + title = title.decode('utf-8') + except: + pass + self._connect() + self.cur.execute('UPDATE downloads SET jsoninfo = "' + urllib.quote_plus(json.dumps(info)) + '" where title="' + title+'"') + self.db.commit() + self._close() + + def delete(self, addtime): + self._connect() + self.cur.execute('delete from downloads where addtime="' + addtime + '"') + self.db.commit() + self._close() + + def clear(self): + self._connect() + self.cur.execute('delete from downloads') + self.db.commit() + self._close() + + def _connect(self): + dirname = xbmc.translatePath('special://temp') + for subdir in ('xbmcup', 'plugin.video.torrenter'): + dirname = os.path.join(dirname, subdir) + if not xbmcvfs.exists(dirname): + xbmcvfs.mkdir(dirname) + + self.filename = os.path.join(dirname, self.name) + + first = False + if not xbmcvfs.exists(self.filename): + first = True + + self.db = sqlite.connect(self.filename, check_same_thread=False) + if not first: + self.cur = self.db.cursor() + try: + self.cur.execute('select version from db_ver') + row = self.cur.fetchone() + if not row or float(row[0]) != self.version: + self.cur.execute('drop table downloads') + self.cur.execute('drop table if exists db_ver') + first = True + self.db.commit() + self.cur.close() + except: + self.cur.execute('drop table downloads') + first = True + self.db.commit() + self.cur.close() + + if first: + cur = self.db.cursor() + cur.execute('pragma auto_vacuum=1') + cur.execute('create table db_ver(version real)') + cur.execute( + 'create table downloads(addtime integer PRIMARY KEY, title varchar(32), path varchar(32), type varchar(32), jsoninfo varchar(32))') + cur.execute('insert into db_ver(version) values(?)', (self.version, )) + self.db.commit() + cur.close() + self.cur = self.db.cursor() + + def _close(self): + self.cur.close() + self.db.close() \ No newline at end of file diff --git a/icons/download.png b/icons/download.png new file mode 100644 index 0000000..bb32d5b Binary files /dev/null and b/icons/download.png differ diff --git a/icons/list.png b/icons/list.png index ae64f38..3922c87 100644 Binary files a/icons/list.png and b/icons/list.png differ diff --git a/icons/settings.png b/icons/settings.png index 733487e..b0a3b86 100644 Binary files a/icons/settings.png and b/icons/settings.png differ diff --git a/icons/torrentPlayer.png b/icons/torrentPlayer.png index e9f502e..cb012e3 100644 Binary files a/icons/torrentPlayer.png and b/icons/torrentPlayer.png differ diff --git a/resources/contenters/KickAssSo.py b/resources/contenters/KickAssSo.py new file mode 100644 index 0000000..1ed2a73 --- /dev/null +++ b/resources/contenters/KickAssSo.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +''' + Torrenter plugin for XBMC + Copyright (C) 2012 Vadim Skorba + vadim.skorba@gmail.com + + 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 re +import Content + +class KickAssSo(Content.Content): + category_dict = { + 'hot': ('Hot & New', '/new/', {'page': '/new/%d/', 'increase': 1, 'second_page': 2}), + 'anime': ('Anime', '/anime/', {'page': '/anime/%d/', 'increase': 1, 'second_page': 2}), + 'tvshows': ('TV Shows', '/tv/', {'page': '/tv/%d/', 'increase': 1, 'second_page': 2}), + 'movies': ('Forieng Movies', '/movies/', {'page': '/movies/%d/', 'increase': 1, 'second_page': 2}), + } + + baseurl = "http://kickass.so" + headers = [('User-Agent', + 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124' + \ + ' YaBrowser/14.10.2062.12061 Safari/537.36'), + ('Referer', 'http://kickass.so/'), ('Accept-Encoding', 'gzip')] + ''' + Weight of source with this searcher provided. + Will be multiplied on default weight. + Default weight is seeds number + ''' + sourceWeight = 1 + + def isLabel(self): + return True + + def isScrappable(self): + return False + + def isInfoLink(self): + return True + + def isPages(self): + return True + + def isSearchOption(self): + return False + + def get_contentList(self, category, subcategory=None, page=None): + contentList = [] + url = self.get_url(category, subcategory, page, self.baseurl) + + response = self.makeRequest(url, headers=self.headers) + + if None != response and 0 < len(response): + #print response + if category: + contentList = self.mode(response) + #print str(contentList) + return contentList + + def mode(self, response): + contentList = [] + #print str(result) + num = 51 + good_forums=['TV','Anime','Movies'] + result = re.compile( + r'''(.+?).+? in .+?">(.+?)''', + re.DOTALL).findall(response) + for link,title,forum in result: + #main + if forum in good_forums: + info = {} + num = num - 1 + original_title = None + year = 0 + img = '' + #info + + info['label'] = info['title'] = self.unescape(title) + info['link'] = link + + contentList.append(( + int(int(self.sourceWeight) * (int(num))), + original_title, title, int(year), img, info, + )) + return contentList diff --git a/resources/searchers/NNMClubRu.py b/resources/searchers/NNMClubRu.py index 36f18d0..059c557 100644 --- a/resources/searchers/NNMClubRu.py +++ b/resources/searchers/NNMClubRu.py @@ -19,9 +19,6 @@ ''' import re -import os -#import time -import tempfile import sys import SearcherABC