Esempio n. 1
0
    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.")
Esempio n. 2
0
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()
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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"])
            }
Esempio n. 7
0
    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.")
Esempio n. 8
0
    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.")
Esempio n. 9
0
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
Esempio n. 10
0
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
Esempio n. 11
0
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
Esempio n. 12
0
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),
            }
Esempio n. 13
0
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()
Esempio n. 14
0
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))
Esempio n. 15
0
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()
Esempio n. 16
0
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