def loop(self): from xbmctorrent.utils import SafeDialogProgress has_resolved = False plugin.log.info("Starting torrent2http...") with closing(torrent2http.start(**self.torrent2http_options)) as t2h_instance: t2h = lambda cmd: url_get_json("http://%s/%s" % (t2h_instance.bind_address, cmd), with_immunicity=False) if not self._wait_t2h_startup(t2h): return plugin.log.info("Opening download dialog...") with closing(SafeDialogProgress(delay_create=0)) as dialog: dialog.create(plugin.name) plugin.log.info("Waiting for file resolution...") while not has_resolved: if xbmc.abortRequested or dialog.iscanceled(): return status = t2h("status") self.display_name = status["name"] if status["state"] < 3: dialog.update(0, *self._get_status_lines(status)) if status["state"] >= 3 and not has_resolved: # Downloading? files = t2h("ls")["files"] biggest_file = sorted(files, key=lambda x: x["size"])[-1] biggest_file["name"] = biggest_file["name"].encode("utf-8") dialog.update(int(biggest_file["buffer"] * 100.0), *self._get_status_lines(status)) if biggest_file["buffer"] >= 1.0: plugin.log.info("Resolving to http://%s/files/%s" % (t2h_instance.bind_address, biggest_file["name"])) has_resolved = True item = { "path": "http://%s/files/%s" % (t2h_instance.bind_address, urllib.quote(biggest_file["name"])), } if not xbmc.getInfoLabel("ListItem.Title"): item["label"] = self.display_name plugin.set_resolved_url(item) break xbmc.sleep(TORRENT2HTTP_POLL) # We are now playing plugin.log.info("Now playing torrent...") last_playing_event = 0 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(): overlay.text = "\n".join(self._get_status_lines(t2h("status"))) now = time.time() if (now - last_playing_event) > PLAYING_EVENT_INTERVAL: track_event("video", "playing", self.display_name) last_playing_event = now xbmc.sleep(TORRENT2HTTP_POLL) plugin.log.info("Closing Torrent player.")
def lostfilm_all(): from bs4 import BeautifulSoup from urlparse import urljoin from contextlib import closing from xbmctorrent.utils import SafeDialogProgress with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1=u"Получение информации ...", line2="", line3="") try: html_data = url_get(urljoin(BASE_URL, "serials.php"), headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib", from_encoding="windows-1251") div_mid = soup.select("div.mid") tvshows = div_mid[0].findAll("a", class_="bb_a") except: plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, u"Не удалось получить данные от сервера") return done = 0 for tvshow in tvshows: tvshowid = tvshow["href"].replace("/browse.php?cat=", "") tvshow_name = "[COLOR FFFFFFFF][B]%s[/B][/COLOR] %s" % (tvshow.contents[0], tvshow.contents[2].text) if dialog.iscanceled(): return item = _lostfilm_updateitem_from_db({ "label" : tvshow_name, "path" : plugin.url_for("lostfilm_tvshow", showid=tvshowid, season=0), "is_playable" : False, "info" : { "title" : "%s %s" % (tvshow.contents[0], tvshow.contents[2].text) } }, tvshowid) done += 1 dialog.update( percent = int(done * 100.0 / len(tvshows)), line2 = item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"], line3 = "" ) yield item; _lostfilm_close_dbase()
def rutracker_page(catind, page, query=None): import urllib, xbmc from bs4 import BeautifulSoup, SoupStrainer from urlparse import urljoin from contextlib import closing from itertools import izip from concurrent import futures from multiprocessing.pool import ThreadPool from xbmctorrent.utils import terminating, SafeDialogProgress from urlparse import urlparse scraper_name = "" category = ([cat for cat in CATEGORIES if cat[0] == catind] or [("0", u"", "", "")])[0] scraper_name = category[3] plugin.set_content(category[2]) page = int(page) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1=u"Получение информации о раздачах...", line2="", line3="") items = [] try: start_index = 0 url = urljoin( BASE_URL, "viewforum.php?f=%s&start=%s" % (query, str(page * 50))) html_data = url_get(url, headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib") # find subforums nodes = soup.findAll("h4", class_=["forumlink"]) #Add search item on topmost page: if catind == query: yield { "label": u"[COLOR FFFFFF00][ Поиск ][/COLOR]", "path": plugin.url_for("rutracker_search", catind=catind), } plugin.log.debug("Loading forum nodes") for node in nodes: link = node.find("a") plugin.log.debug("Forum link: " + str(link)) link_href = link["href"] # find forum id in href: forumid = int(link_href[link_href.find(u"=") + 1:len(link_href)]) item = { "label": link.text, "path": plugin.url_for("rutracker_page", catind=catind, page=0, query=forumid), "info": { "title": link.text }, "is_playable": False, } yield item nodes = soup.findAll("td", class_=["topic_id"]) for node in nodes: id = node["id"] title_node = node.parent.find(id='tt-%s' % str(id)) title = _rutracker_cleantitle(title_node.text) row_node = node.parent \ #find "size" table cell - it should have download link size_td = row_node.find_all("td")[2] #check if size node has download link to torrent file: if size_td: size_link = size_td.find("a", class_=["small"]) if size_link: size = size_link.text seeds = size_td.find("span", class_=["seedmed"]).b.text peers = size_td.find("span", class_=["leechmed"]).b.text size = size_td.find("a", class_=["small"]).text label = "%s | %s (S:%s P:%s)" % (title, size, seeds, peers) item = { "label": label, "path": plugin.url_for("rutracker_play", tid=id), "info": { "title": title }, "is_playable": False, "context_menu": [("Play with Pulsar", actions.update_view( plugin.url_for("rutracker_play_pulsar", tid=id)))] } items.append(item) plugin.log.debug("Item added: " + title.encode('utf-8')) except: plugin.log.error("Unexpected error: %s" % format_exc().split('\n')[-2]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return def _get_torrent_info(item): from xbmctorrent.search import scrapers as search from xbmctorrent.utils import get_quality_from_name try: scrapers = search.Scrapers() if not plugin.get_setting("rutracker_usesearch", bool): meta = scrapers.default(item) else: meta = scrapers.scraper(scraper_name, item) meta["path"] = item["path"] meta["is_playable"] = item["is_playable"] meta.setdefault("stream_info", {}).update( get_quality_from_name(meta['label'])) return meta except: plugin.log.error("Unexpected error: %s" % format_exc().split('\n')[-2]) return scrapers.default(item) state = {"done": 0} def on_done(data): state["done"] += 1 dialog.update( percent=int(state["done"] * 100.0 / len(items)), line2=data["info"].get("title") or data.get("label") or "", ) with terminating(ThreadPool(5)) as pool: jobs = [ pool.apply_async(_get_torrent_info, [item], callback=on_done) for item in items ] while not all(job.ready() for job in jobs): if dialog.iscanceled(): return xbmc.sleep(100) for job in jobs: item = job.get() del item["search"] del item["subdir"] yield item next_page = { "label": u"[Далее >]", "path": plugin.url_for("rutracker_page", catind=catind, page=page + 1, query=query), "is_playable": False, } yield next_page
def rutracker_play(tid, pulsar): from copy import deepcopy from contextlib import closing from bencode import bencode, bdecode from urlparse import urljoin from xbmctorrent.magnet import generate_magnet from xbmctorrent.utils import first, SafeDialogProgress, get_quality_from_name, get_current_list_item from xbmctorrent.acestream import ace_supported with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Получение информации о раздаче...") torrent_url = urljoin("http://dl.rutracker.org/forum/", "dl.php?t=%s" % tid) try: plugin.log.debug("loading data from uri: " + torrent_url) params = {"t": tid} import os, xbmc, cookielib cookie = cookielib.Cookie(version=0, name='bb_dl', value=tid, port=None, port_specified=False, domain='.rutracker.org', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False) data = url_get(torrent_url, headers=HEADERS, post=params, cookie=cookie) metadata = bdecode(data) plugin.log.debug("Metadata received " + str(metadata)) except: import xbmcgui plugin.log.error("Unexpected error: %s " % format_exc().split('\n')[-2]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return dialog.update(percent=100, line1="Готово") # Get currently selected item current_item = get_current_list_item() current_item.setdefault("stream_info", {}).update( get_quality_from_name(current_item['label'])) if "files" in metadata["info"] and ace_supported(): items = {} for index, info in enumerate(metadata["info"]["files"]): name = "/".join(info["path"]) if not _rutracker_valid_file(name): continue items[index] = deepcopy(current_item) items[index].update({ "label": name, "path": plugin.url_for("play_torrent_raw", raw=data, index=index, name=name), "is_playable": True }) items[index].setdefault("info", {}).update({ "title": name, }) # start playback if torrent contains only one file if len(items) == 1: index, item = items.popitem() if not plugin.get_setting("force_ace", bool): item["path"] = plugin.url_for("play", uri=generate_magnet( metadata, item["label"])) plugin.play_video(item) yield item else: plugin.add_sort_method('label') for i in items.values(): yield i else: name = metadata["info"].get("name") or " / ".join( first(metadata["info"]["files"])["path"]) or "rutor.org" if plugin.get_setting("force_ace", bool) and ace_supported(): current_item["path"] = plugin.url_for("play_torrent_raw", raw=data, index=0, name=name) else: current_item["path"] = plugin.url_for( ["play", "play_with_pulsar"][int(pulsar)], uri=generate_magnet(metadata, name)) current_item["is_playable"] = True plugin.play_video(current_item) yield current_item
def rutracker_search_page(catind, page, search=None, search_id=None): import urllib, xbmc from bs4 import BeautifulSoup, SoupStrainer from urlparse import urljoin from contextlib import closing from itertools import izip from concurrent import futures from multiprocessing.pool import ThreadPool from xbmctorrent.utils import terminating, SafeDialogProgress from urlparse import urlparse scraper_name = "" category = ([cat for cat in CATEGORIES if cat[0] == catind] or [("0", u"", "", "")])[0] scraper_name = category[3] plugin.set_content(category[2]) if plugin.request.args.get("search_id"): search_id = plugin.request.args.get("search_id")[0] page = int(page) catind = int(catind) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1=u"Получение информации о раздачах...", line2="", line3="") items = [] try: start_index = 0 url = urljoin(BASE_URL, "search.php?") if search_id: params = {} params["nm"] = search if int(page) > 0: params["start"] = int(page) * 50 params["id"] = search_id html_data = url_get(url, headers=HEADERS, params=params) else: post_body = {"nm": search, "fsf": catind} html_data = url_get(url, headers=HEADERS, post=post_body) soup = BeautifulSoup(html_data, "html5lib") node = soup.find("a", class_=["pg"]) if node: r = search_id_parser.search(node['href']) if r: plugin.log.debug("Search id found: " + str(r.group(1))) search_id = str(r.group(1)) nodes = soup.findAll("a", class_=["topictitle"]) for link in nodes: try: title = _rutracker_cleantitle(link.text) r = topic_id_parser.search(link['href']) if r: id = r.group(1) label = "%s" % (title) item = { "label": label, "path": plugin.url_for("rutracker_play", tid=id), "info": { "title": title }, "is_playable": False, "context_menu": [("Play with Pulsar", actions.update_view( plugin.url_for("rutracker_play_pulsar", tid=id)))] } items.append(item) plugin.log.debug("Item added: " + title.encode('utf-8')) except: plugin.log.error("Unexpected error: %s \r Skipping item" % format_exc().split('\n')[-2]) except: plugin.log.error("Unexpected error: %s" % format_exc().split('\n')[-2]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return def _get_torrent_info(item): from xbmctorrent.search import scrapers as search from xbmctorrent.utils import get_quality_from_name try: scrapers = search.Scrapers() if not plugin.get_setting("rutracker_usesearch", bool): meta = scrapers.default(item) else: meta = scrapers.scraper(scraper_name, item) plugin.log.debug("RUTRACKER: Meta information received") meta["path"] = item["path"] meta["is_playable"] = item["is_playable"] meta.setdefault("stream_info", {}).update( get_quality_from_name(meta['label'])) plugin.log.debug("RUTRACKER: Meta path updated") return meta except: plugin.log.error( "RUTRACKER: Unexpected error: %s parsing item [%s]" % (format_exc().split('\n')[-2], str(item))) return scrapers.default(item) state = {"done": 0} def on_done(data): state["done"] += 1 dialog.update( percent=int(state["done"] * 100.0 / len(items)), line2=data["info"].get("title") or data.get("label") or "", ) with terminating(ThreadPool(5)) as pool: jobs = [ pool.apply_async(_get_torrent_info, [item], callback=on_done) for item in items ] while not all(job.ready() for job in jobs): if dialog.iscanceled(): return xbmc.sleep(100) for job in jobs: try: item = job.get() del item["search"] del item["subdir"] yield item except: plugin.log.error( "RUTRACKER: Unexpected error: %s parsing item [%s]" % (format_exc().split('\n')[-2], str(item))) if search_id: next_page = { "label": u"[Далее >]", "path": plugin.url_for("rutracker_search_page", catind=catind, page=page + 1, search=search, search_id=search_id), "is_playable": False, } yield next_page
def eztv_shows_by_letter(letter): import re import xbmc import xbmcgui from bs4 import BeautifulSoup from contextlib import nested, closing from itertools import izip, groupby from concurrent import futures from xbmctorrent.scrapers import ungenerate from xbmctorrent.utils import terminating, url_get, SafeDialogProgress from xbmctorrent import tvdb with shelf("it.eztv.shows") as eztv_shows: if not eztv_shows: response = url_get("%s/showlist/" % BASE_URL, headers=HEADERS) soup = BeautifulSoup(response, "html5lib") nodes = soup.findAll("a", "thread_link") for node in nodes: show_id, show_named_id = node["href"].split("/")[2:4] show_name = node.text show_first_letter = show_name[0].lower() if re.match("\d+", show_first_letter): show_first_letter = "0-9" eztv_shows.setdefault(show_first_letter, {}).update({ show_id: { "id": show_id, "named_id": show_named_id, "name": node.text, } }) shows_list = sorted(eztv_shows[letter.lower()].values(), key=lambda x: x["name"].lower()) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Fetching serie information...", line2="", line3="") state = {"done": 0} def on_serie(future): data = future.result() state["done"] += 1 dialog.update( percent=int(state["done"] * 100.0 / len(shows_list)), line2=data and data["seriesname"] or "", ) with futures.ThreadPoolExecutor(max_workers=5) as pool_tvdb: tvdb_list = [pool_tvdb.submit(tvdb.search, show["name"], True) for show in shows_list] [future.add_done_callback(on_serie) for future in tvdb_list] while not all(job.done() for job in tvdb_list): if dialog.iscanceled(): return xbmc.sleep(100) tvdb_list = [job.result() for job in tvdb_list] for i, (eztv_show, tvdb_show) in enumerate(izip(shows_list, tvdb_list)): if tvdb_show: item = tvdb.get_list_item(tvdb_show) item.update({ "path": plugin.url_for("eztv_get_show_seasons", show_id=eztv_show["id"], tvdb_id=tvdb_show["id"]) }) yield item else: yield { "label": eztv_show["name"], "path": plugin.url_for("eztv_get_show_seasons", show_id=eztv_show["id"]) }
def loop(self): from xbmctorrent.utils import SafeDialogProgress has_resolved = False plugin.log.info("Starting torrent2http...") with closing(torrent2http.start( **self.torrent2http_options)) as t2h_instance: t2h = lambda cmd: url_get_json("http://%s/%s" % (t2h_instance.bind_address, cmd)) track_event("video", "download", self.magnet_display_name) if not self._wait_t2h_startup(t2h): return plugin.log.info("Opening download dialog...") with closing(SafeDialogProgress(delay_create=0)) as dialog: dialog.create(plugin.name) plugin.log.info("Waiting for file resolution...") while not has_resolved: if xbmc.abortRequested or dialog.iscanceled(): return status = t2h("status") if status["state"] >= 0: dialog.update(int(status["progress"] * 100), *self._get_status_lines(status)) if status[ "state"] >= 3 and not has_resolved: # Downloading? files = t2h("ls")["files"] biggest_file = sorted(files, key=lambda x: x["size"])[-1] percent_complete = float( biggest_file["complete_pieces"]) / float( biggest_file["total_pieces"]) * 100.0 if percent_complete >= 0.5: plugin.log.info("Resolving to http://%s/files/%s" % (t2h_instance.bind_address, biggest_file["name"])) has_resolved = True url_name = "/".join( map(urllib.quote, biggest_file["name"].split("/"))) plugin.set_resolved_url({ "label": self.magnet_display_name, "label2": self.magnet_display_name, "path": "http://%s/files/%s" % (t2h_instance.bind_address, url_name), "is_playable": True, }) break xbmc.sleep(TORRENT2HTTP_POLL) # We are now playing plugin.log.info("Now playing torrent...") last_playing_event = 0 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(): overlay.text = "\n".join( self._get_status_lines(t2h("status"))) now = time.time() if (now - last_playing_event) > PLAYING_EVENT_INTERVAL: track_event("video", "playing", self.magnet_display_name) last_playing_event = now xbmc.sleep(TORRENT2HTTP_POLL) plugin.log.info("Closing Torrent player.")
def loop(self): from xbmctorrent.utils import SafeDialogProgress from xbmctorrent.player import OverlayText has_resolved = False plugin.log.info("Starting AceStream...") def safe_cast(val, to_type, default=None): try: return to_type(val) except ValueError: return default engine_params = { "filename": self.file_name, "host": plugin.get_setting("ace_host", str) or DEFAULT_ACESTREAM_HOST, "port": safe_cast(plugin.get_setting("ace_port"), int, DEFAULT_ACESTREAM_PORT), "keep_enc": plugin.get_setting("ace_keep_encripted", bool) } if plugin.get_setting("keep_files", bool): plugin.log.info("Will keep file after playback.") engine_params["dlpath"] = xbmc.validatePath( xbmc.translatePath( plugin.get_setting("dlpath") or "special://temp/" + plugin.id)) if engine_params["dlpath"] and "://" in engine_params["dlpath"]: # Translate smb:// url to UNC path on windows, very hackish if PLATFORM["os"] == "windows" and engine_params[ "dlpath"].lower().startswith("smb://"): engine_params["dlpath"] = engine_params["dlpath"].replace( "smb:", "").replace("/", "\\") with closing(AceEngine(**engine_params)) as engine: plugin.log.info("Opening download dialog...") # Get currently selected item current_item = get_current_list_item() with closing(SafeDialogProgress(delay_create=0)) as dialog: dialog.create("AceStream Player") connected = engine.try_to_connect() ready = False n = 1 start = time.time() while (time.time() - start) < ACESTREAM_CONNECTION_TIMEOUT: if xbmc.abortRequested or dialog.iscanceled(): return dialog.update(0, self.file_name, "Попытка соединения с AceStream (%s)" % n) if not connected: plugin.log.info("Starting AceStream engine") if engine.start(): xbmc.sleep(ACESTREAM_CONNECTION_POLL) connected = engine.try_to_connect() continue else: if engine.is_ready(): break plugin.log.info("Engine is not ready") xbmc.sleep(ACESTREAM_CONNECTION_POLL) n = n + 1 if not engine.is_ready(): return dialog.update( 0, self.file_name, "Соединение установлено. Запуск загрузки данных...") if not engine.play( self.torrent, self.index, is_raw=self.is_raw): return while not has_resolved: if xbmc.abortRequested or dialog.iscanceled(): return status = engine.get_status() if status["error"]: dialog.update( int(status["progress"]), *[ self.file_name, STATE_STRS[status["status"]], status["error"] ]) xbmc.sleep(PLAYING_EVENT_INTERVAL) return if status["state"] > 0 and status["status"]: dialog.update(int(status["progress"]), *self._get_status_lines(status)) if status["state"] >= 2 and status[ "status"] == "dl" and not has_resolved: # Downloading? if int(status["progress"]) >= 0: plugin.log.info("Resolving to %s" % status["url"]) has_resolved = True if not current_item["info"].get("title"): current_item["label"] = self.file_name current_item["path"] = status["url"] plugin.set_resolved_url(current_item) break xbmc.sleep(PLAYING_EVENT_INTERVAL) # We are now playing plugin.log.info("Now playing torrent...") 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), self.attach(engine.on_start, self.on_playback_started), self.attach(engine.on_pause, self.on_playback_paused), self.attach(engine.on_resume, self.on_playback_resumed), self.attach(engine.on_stop, self.on_playback_stopped), self.attach(engine.on_seek, self.on_playback_seek), self.attach(engine.on_end, self.on_playback_ended), self.attach(self.pause, engine.on_playback_paused), self.attach(self.play, engine.on_playback_resumed)): while not xbmc.abortRequested and self.isPlaying( ) and not engine.error: overlay.text = "\n".join( self._get_status_lines(engine.get_status())) xbmc.sleep(PLAYING_EVENT_INTERVAL) plugin.log.info("Closing AceStream player.")
def rutor_play(tid, pulsar): from copy import deepcopy from contextlib import closing from bencode import bencode, bdecode from urlparse import urljoin from xbmctorrent.magnet import generate_magnet from xbmctorrent.utils import first, SafeDialogProgress, get_quality_from_name, get_current_list_item from xbmctorrent.acestream import ace_supported with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Получение информации о раздаче...") torrent_url = urljoin(DOWNLOAD_URL, "download/%s" % tid) try: metadata = bdecode(url_get(torrent_url, headers=HEADERS)) except: import xbmcgui plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return dialog.update(percent=100, line1="Готово") # Get currently selected item current_item = get_current_list_item() current_item.setdefault("stream_info", {}).update( get_quality_from_name(current_item['label'])) if "files" in metadata["info"] and ace_supported(): items = {} for index, info in enumerate(metadata["info"]["files"]): name = "/".join(info["path"]) if not _rutor_valid_file(name): continue items[index] = deepcopy(current_item) items[index].update({ "label": name, "path": plugin.url_for("torrent_play", url=torrent_url, index=index, name=name), "is_playable": True }) items[index].setdefault("info", {}).update({ "title": name, }) # start playback if torrent contains only one file if len(items) == 1: index, item = items.popitem() if not plugin.get_setting("force_ace", bool): item["path"] = plugin.url_for("play", uri=generate_magnet( metadata, item["label"])) plugin.play_video(item) yield item else: plugin.add_sort_method('label') for i in items.values(): yield i else: name = metadata["info"].get("name") or " / ".join( first(metadata["info"]["files"])["path"]) or "rutor.org" if plugin.get_setting("force_ace", bool) and ace_supported(): current_item["path"] = plugin.url_for("torrent_play", url=torrent_url, index=0, name=name) else: current_item["path"] = plugin.url_for( ["play", "play_with_pulsar"][int(pulsar)], uri=generate_magnet(metadata, name)) current_item["is_playable"] = True plugin.play_video(current_item) yield current_item
def rutor_page(catind, page, query=None): import urllib, xbmc from bs4 import BeautifulSoup, SoupStrainer from urlparse import urljoin from contextlib import closing from itertools import izip from concurrent import futures from multiprocessing.pool import ThreadPool from xbmctorrent.utils import terminating, SafeDialogProgress scraper_name = "" category = ([cat for cat in CATEGORIES if cat[0] == catind] or [("0", u"", "", "")])[0] scraper_name = category[3] plugin.set_content(category[2]) page = int(page) catind = int(catind) mode = "browse" if query and query != str(None): mode = "search" with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1=u"Получение информации о раздачах...", line2="", line3="") nodes = [] try: html_data = url_get(urljoin( BASE_URL, "%s/%d/%d/0/0/%s" % (mode, page, catind, query)), headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib") nodes = soup.findAll("tr", class_=["gai", "tum"]) except: import xbmcgui plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return if not nodes or len(nodes) == 0: yield { "label": u"[ Не найдено ]", "path": plugin.url_for("rutor_index"), "is_playable": False, } return # store length before filter nodeslen = len(nodes) nodes = [node for node in _rutor_filter_nodes(nodes)] items = [] for node in nodes: cells = node.findAll("td") seeds, peers = map(lambda x: x.text.strip(), cells[len(cells) - 1].findAll("span")) links = cells[1].findAll("a") magnet_node, title_node = [ links[len(links) - 2], links[len(links) - 1] ] size = cells[len(cells) - 2].text tid = int(title_node["href"][9:title_node["href"].find(u"/", 9)]) title = _rutor_cleantitle(title_node.text) label = "%s | %s (S:%s P:%s)" % (title, size, seeds, peers) item = { "label": label, "path": plugin.url_for("rutor_details", catind=catind, tid=tid), "info": { "title": title }, "is_playable": False, } items.append(item) def _get_torrent_info(item): from xbmctorrent.search import scrapers as search from xbmctorrent.utils import get_quality_from_name scrapers = search.Scrapers() if not plugin.get_setting("rutor_usesearch", bool): meta = scrapers.default(item) else: meta = scrapers.scraper(scraper_name, item) meta["path"] = item["path"] meta["is_playable"] = item["is_playable"] meta.setdefault("stream_info", {}).update(get_quality_from_name(meta['label'])) return meta state = {"done": 0} def on_done(data): state["done"] += 1 dialog.update( percent=int(state["done"] * 100.0 / len(nodes)), line2=data["info"].get("title") or data.get("label") or "", ) with terminating(ThreadPool(5)) as pool: jobs = [ pool.apply_async(_get_torrent_info, [item], callback=on_done) for item in items ] while not all(job.ready() for job in jobs): if dialog.iscanceled(): return xbmc.sleep(100) import hashlib passed = {} for job in jobs: item = job.get() sha1 = hashlib.sha1( uenc( item.get("subdir") and item["subdir"] or (item.get("search") and item["search"] or item["label"]))).hexdigest() if not passed.get(sha1): passed[sha1] = True del item["search"] del item["subdir"] yield item if nodeslen == 100: next_page = { "label": u"[Далее >]", "path": plugin.url_for("rutor_page", catind=catind, page=page + 1, query=query), "is_playable": False, } yield next_page
def torrents3d_play(article): import re, xbmcgui from bs4 import BeautifulSoup from contextlib import closing from urlparse import urljoin from xbmctorrent.magnet import generate_magnet from xbmctorrent.utils import SafeDialogProgress article = int(article) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1=u"Получение информации о релизе...", line2="", line3="") url = urljoin(BASE_URL, "article/%d" % article) try: html_data = url_get(url, headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib") torrent_href = soup.find("a", class_="genmed") if not torrent_href: dialog.update(percent=50, line2=u"Требуется авторизация. Авторизация...") if not plugin.get_setting( "t3d_login") and not plugin.get_setting("t3d_passwd"): plugin.notify("Проверьте настройки авторизации.", delay=15000) return html_data = _torrents3d_login(url) soup = BeautifulSoup(html_data, "html5lib") torrent_href = soup.find("a", class_="genmed") if not torrent_href: xbmcgui.Dialog().ok( plugin.name, "Авторизация неудалась. Проверьте настройки авторизации.") return dialog.update(percent=100, line2=u"Обработка данных.") from bencode import bencode, bdecode title = "[%s] %s" % _torrents3d_cleantitle( soup.find("a", class_="tt-text").text) torrent_data = url_get(torrent_href["href"], headers=HEADERS) metadata = bdecode(torrent_data) plugin.redirect( plugin.url_for("play", uri=generate_magnet(metadata, uenc(title)))) except: plugin.log.error("Cannot get data from remote server") xbmcgui.Dialog().ok(plugin.name, u"Не удалось получить данные от сервера") return
def yify_show_data(callback): import xbmc import xbmcgui from contextlib import nested, closing from itertools import izip, chain from concurrent import futures from xbmctorrent import tmdb from xbmctorrent.utils import url_get_json, terminating, SafeDialogProgress plugin.set_content("movies") args = dict((k, v[0]) for k, v in plugin.request.args.items()) current_page = int(args["set"]) limit = int(args["limit"]) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Fetching movie information...", line2="", line3="") try: search_result = url_get_json("%s/api/list.json" % BASE_URL, params=args, headers=HEADERS) except: plugin.notify("Unable to connect to %s." % BASE_URL) raise movies = search_result.get("MovieList") or [] if not movies: return state = {"done": 0} def on_movie(future): data = future.result() state["done"] += 1 dialog.update( percent=int(state["done"] * 100.0 / len(movies)), line2=data.get("title") or data.get("MovieTitleClean") or "", ) with futures.ThreadPoolExecutor(max_workers=2) as pool_tmdb: tmdb_list = [ pool_tmdb.submit(tmdb.get, movie["ImdbCode"]) for movie in movies ] [future.add_done_callback(on_movie) for future in tmdb_list] while not all(job.done() for job in tmdb_list): if dialog.iscanceled(): return xbmc.sleep(100) tmdb_list = map(lambda job: job.result(), tmdb_list) for movie, tmdb_meta in izip(movies, tmdb_list): if tmdb_meta: magnet_link = urllib.quote_plus( movie["TorrentMagnetUrl"].encode("utf-8")) item = tmdb.get_list_item(tmdb_meta) if args.get("quality") == "all" and movie["Quality"] != "720p": item["label"] = "%s (%s)" % (item["label"], movie["Quality"]) item.update({ "path": "plugin://plugin.video.pulsar/play?uri=" + magnet_link, # "path": plugin.url_for("play", uri=movie["TorrentMagnetUrl"]), "is_playable": True, }) item.setdefault("info", {}).update({ "count": movie["MovieID"], "genre": "%s (%s S:%s P:%s)" % (item["info"]["genre"], movie["Size"], movie["TorrentSeeds"], movie["TorrentPeers"]), "plot_outline": tmdb_meta["overview"], "video_codec": "h264", }) width = 1920 height = 1080 if movie["Quality"] == "720p": width = 1280 height = 720 item.setdefault("stream_info", {}).update({ "video": { "codec": "h264", "width": width, "height": height, }, "audio": { "codec": "aac", }, }) yield item if current_page < (int(search_result["MovieCount"]) / limit): next_args = args.copy() next_args["set"] = int(next_args["set"]) + 1 yield { "label": ">> Next page", "path": plugin.url_for(callback, **next_args), }
def lostfilm_index(page = ""): from bs4 import BeautifulSoup from urlparse import urljoin from contextlib import closing from xbmctorrent.utils import SafeDialogProgress from xbmctorrent.acestream import ace_supported page = int(page) with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Получение информации ...", line2="", line3="") try: html_data = url_get(urljoin(BASE_URL, "browse.php"), params={"o":page*15}, headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib", from_encoding="windows-1251") div_body = soup.select("div.content_body") episodes = div_body[0].findAll("span", class_="torrent_title") except: plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера.") return yield { "label": "[COLOR FF00FF00][Полный список сериалов][/COLOR]", "path": plugin.url_for("lostfilm_all"), } done = 0 for episode in episodes: tvshow_name = episode.find_previous_sibling("a").img["title"] # needs if not found in db a_download = episode.find_next("a", class_="a_download")["onclick"] tvshowid, season, episode_num = a_download[a_download.rfind("(")+2:a_download.rfind(")")-1].split("','") if dialog.iscanceled(): return item = _lostfilm_updateitem_from_db({ "label" : "[COLOR FFFFFFCC][%s.%s][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR]: %s" % (season, episode_num, tvshow_name, episode.text), "path" : plugin.url_for("lostfilm_play", showid=tvshowid, season=season, episode=episode_num), "is_playable" : True, "info" : { "title" : episode.text, "season" : season, "episode" : episode_num } }, tvshowid) if not "-" in episode_num and int(episode_num) == 99: item.update({ "label" : "[COLOR FFFFFFCC][%s.xx][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR]: %s" % (season, tvshow_name, episode.text), "is_playable" : not ace_supported(), "info" : { "title" : episode.text, "season" : season, "episode" : "all" } }) done += 1 dialog.update( percent = int(done * 100.0 / len(episodes)), line2 = item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"], line3 = "" ) yield item; if len(episodes) >= 15: yield { "label": "[COLOR FF00FF00][Далее >][/COLOR]", "path": plugin.url_for("lostfilm_index", page=page + 1), } _lostfilm_close_dbase()
def lostfilm_play(showid, season, episode): import re, xbmcgui from urlparse import urljoin from contextlib import closing from bs4 import BeautifulSoup from xbmctorrent.acestream import ace_supported from xbmctorrent.magnet import generate_magnet from xbmctorrent.utils import SafeDialogProgress, get_quality_from_name with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Получение информации о релизе...", line2="", line3="") params = { "c" : showid, "s" : season, "e" : episode } try: html = url_get(urljoin(BASE_URL, "nrdr.php"), params=params) # catch 'log in first' then login if html.find("log in first") >= 0: dialog.update(percent=10, line2="Требуется авторизация. Авторизация...") if not plugin.get_setting("lostfilm_login") and not plugin.get_setting("lostfilm_passwd"): plugin.notify("Проверьте настройки авторизации.", delay=15000) return _lostfilm_login() dialog.update(percent=30, line2="Загрузка.", line3="") html = url_get(urljoin(BASE_URL, "nrdr.php"), params=params) if html.find("log in first") >= 0: xbmcgui.Dialog().ok(plugin.name, "Авторизация неудалась. Проверьте настройки.") return except: plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return dialog.update(percent=50, line2="Обработка данных.") soup = BeautifulSoup(html, "html5lib", from_encoding="windows-1251") releases = soup.findAll("a", href=re.compile("tracktor.in"), style=re.compile("bold")) select_items = [] for release in releases: span = release.find_next("span") select_items.append(span.contents[0]) select = xbmcgui.Dialog().select("Выберите желаемое качество", select_items) if select >= 0: selected = releases[select] torrent_url = selected["href"] if ((not "-" in episode and int(episode) == 99) or ("." in season and "-" in episode)) and ace_supported(): if "." in season: season = season[:season.find(u".")] show_info = _lostfilm_get_db_info(showid) plugin.add_sort_method("label") try: from bencode import bencode, bdecode torrent_data = url_get(torrent_url, headers=HEADERS) metadata = bdecode(torrent_data) except: plugin.log.error("Cannot get data from remote server") xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return e = re.compile("(e[\d]+)?e([\d]+)\.", re.I|re.S|re.U) for index, item in enumerate(metadata["info"]["files"]): file_name = " / ".join(item["path"]) print file_name r = e.search(file_name) if r: if r.group(1): episode = r.group(1)[1:] else: episode = r.group(2) else: episode = u"" yield _lostfilm_updateitem_from_info({ "label" : file_name, "path" : plugin.url_for("torrent_play", url=torrent_url, index=index, name=file_name), "is_playable" : True, "info" : { "title" : file_name, "season" : season, "episode" : episode }, "stream_info" : get_quality_from_name(file_name) }, show_info) _lostfilm_close_dbase() else: plugin.redirect(plugin.url_for("play", uri=torrent_url))
def lostfilm_tvshow(showid, season): from bs4 import BeautifulSoup from urlparse import urljoin from contextlib import closing from xbmctorrent.utils import SafeDialogProgress from xbmctorrent.acestream import ace_supported with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Получение информации ...", line2="", line3="") try: html_data = url_get(urljoin(BASE_URL, "browse.php"), params={"cat" : showid}, headers=HEADERS) soup = BeautifulSoup(html_data, "html5lib", from_encoding="windows-1251") div_mid = soup.select("div.mid") episodes = div_mid[0].findAll("td", class_="t_episode_title") except: import xbmcgui plugin.log.error("Unexpected error: %s" % sys.exc_info()[0]) xbmcgui.Dialog().ok(plugin.name, "Не удалось получить данные от сервера") return show_info = _lostfilm_get_db_info(showid) showid = int(showid) season = int(season) done = 0 for episode in episodes: script = episode["onclick"] tvshowid, season_num, episode_num = script[script.rfind("(")+2:script.rfind(")")-1].split("','") if season > 0 and season != int(season_num): continue is_full_season = (not "-" in episode_num and int(episode_num) == 99) or ("." in season_num and "-" in episode_num) nobr = episode.findAll("nobr")[0] if is_full_season: episode_name = nobr.contents[0].text label = "[COLOR FFFFFFCC][%s.xx][/COLOR] [COLOR FF00FF00][B]%s[/B][/COLOR]" % (season_num, episode_name) else: episode_name = "%s %s" % (nobr.contents[0].text, _safe_list_get(nobr.contents, 2, "")) label = "[COLOR FFFFFFCC][%s.%s][/COLOR] [COLOR FFFFFFFF][B]%s[/B][/COLOR] %s" % ( season_num, episode_num, nobr.contents[0].text, _safe_list_get(nobr.contents, 2, "")) if dialog.iscanceled(): return item = _lostfilm_updateitem_from_info({ "label" : label, "path" : plugin.url_for("lostfilm_play", showid=tvshowid, season=season_num, episode=episode_num), "is_playable" : True, "info" : { "title" : episode_name, "season" : season_num, "episode" : episode_num } }, show_info) if is_full_season and ace_supported(): item.update({ "is_playable" : False }) done += 1 dialog.update( percent = int(done * 100.0 / len(episodes)), line2 = item.get("info", {}).get("tvshowtitle", "") or item.get("info", {}).get("title", "") or item["label"], line3 = "" ) yield item; _lostfilm_close_dbase()
def parse(data, content_type=None): import xbmc import xml.etree.ElementTree as ET from itertools import izip_longest from concurrent import futures from contextlib import nested, closing from xbmctorrent.utils import SafeDialogProgress, get_quality_from_name, get_show_info_from_name, normalize_release_tags from xbmctorrent import tmdb root = ET.fromstring(data) def _text(node, path): n = node.find(path) if n is not None: return n.text def _attr(node, path, attrib): n = node.find(path) if n is not None: return n.attrib.get(attrib) items = [] for node in root.getiterator("item"): item = { "title": _text(node, "title"), "description": _text(node, "description"), "category": _text(node, "category"), "pub_date": _text(node, "pubDate"), "seeds": _text(node, ".//{%(torrent)s}seeds" % NSMAP) or _text(node, "numSeeders") or _text(node, "seeders"), "peers": _text(node, ".//{%(torrent)s}peers" % NSMAP) or _text(node, "numLeechers") or _text(node, "leechers"), "content_length": _text(node, ".//{%(torrent)s}contentLength" % NSMAP) or _attr(node, ".//enclosure", "length"), "href": _text(node, ".//{%(torrent)s}magnetURI" % NSMAP) or _attr(node, ".//enclosure", "url") or _text(node, "./link"), "filename": _text(node, ".//{%(torrent)s}fileName" % NSMAP), } find_image(item) check_imdb_id(item) items.append(item) tmdb_list = [] if content_type: with closing(SafeDialogProgress(delay_close=0)) as dialog: dialog.create(plugin.name) dialog.update(percent=0, line1="Fetching torrent information...", line2="", line3="") with futures.ThreadPoolExecutor(max_workers=POOL_WORKERS) as pool: futures = [] for item in items: if item.get("imdb_id"): futures.append(pool.submit(tmdb.get, item["imdb_id"])) else: futures.append(None) state = {"done": 0} def on_item(future): state["done"] += 1 dialog.update(percent=int(state["done"] * 100.0 / len(filter(None, futures))), ) [ future.add_done_callback(on_item) for future in futures if future ] while not all(future.done() for future in futures if future): if dialog.iscanceled(): return xbmc.sleep(100) tmdb_list = [future and future.result() or None for future in futures] for item, tmdb_data in izip_longest(items, tmdb_list): if tmdb_data: list_item = tmdb.get_list_item(tmdb_data) release_tags = normalize_release_tags(item["title"], list_item["label"]) if release_tags: list_item["label"] = "%s (%s)" % (list_item["label"], release_tags) else: list_item = { "label": item["title"], "icon": item.get("img") or "", "thumbnail": item.get("img") or "", "info": { "genre": item["category"], } } list_item.update({ "path": plugin.url_for("play", uri=item["href"]), "is_playable": True, }) list_item.setdefault("info", {}).update({ "genre": "%s (S:%s P:%s)" % (list_item.get("info", {}).get("genre") or "", item["seeds"], item["peers"]), }) list_item.setdefault("stream_info", {}).update(get_quality_from_name(item["title"])) yield list_item