Ejemplo n.º 1
0
def piratebay_record(node):
    import re
    from xbmctorrent.utils import url_get
    from urlparse import urljoin
    from xbmctorrent import tmdb

    node.seeds, node.peers = map(lambda x: x.text, node.parent.parent.findAll("td")[2:])
    node.magnet_node = node.parent.findAll("a")[1]
    node.desc_node = node.parent.findAll("font", "detDesc")[0]
    node.size = re.search("Size (.*?),", node.desc_node.text).group(1)
    node.txt = "%s (%s S:%s P:%s)" % (node.a.text, node.size.replace(" ", " "), node.seeds, node.peers)

    node.item = {}
    try:
        node.search_result = url_get(urljoin(BASE_URL, node.parent.findAll("a")[0]["href"]), headers=HEADERS)
    except:
        pass
    else:
        if node.search_result:
            try:
                node.imdb_url = re.search("http://www.imdb.com/title/tt[0-9]*", node.search_result).group(0)
            except:
                pass
            else:
                if node.imdb_url:
                    node.imdb_id = re.search(r"(tt\d+)", node.imdb_url).group(0)

                    if node.imdb_id:
                        node.release_tags = tmdb.get_list_item(tmdb.get(node.imdb_id))

                        if node.release_tags:
                            node.item.update(node.release_tags)

    node.item.update({
        "label": node.txt,
        "path": plugin.url_for("play", uri=node.magnet_node["href"]),
        "is_playable": True,
    })
    return node.item
Ejemplo n.º 2
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:
                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.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),
            }
Ejemplo n.º 3
0
def kickass_page(root, page):
    import re
    import xbmc
    import xbmcgui
    from bs4 import BeautifulSoup
    from contextlib import closing
    from concurrent import futures
    from urlparse import urljoin
    from xbmctorrent import tmdb
    from xbmctorrent.utils import first, terminating, url_get, get_quality_from_name

    content_type = first(plugin.request.args.get("content_type")) or None
    if content_type:
        plugin.set_content(content_type)

    page = int(page)
    page_data = url_get(urljoin(BASE_URL, "%s/%d" % (root, page)))
    soup = BeautifulSoup(page_data, "html5lib")
    torrent_nodes = [node.parent for node in soup.findAll("td", "torrentnameCell")]

    def _get_torrent_info_with_meta(url):
        torrent_info = get_torrent_info(url)
        if torrent_info["movie"] and torrent_info["imdb_id"]:
            torrent_info["tmdb"] = tmdb.get(torrent_info["imdb_id"])
        return torrent_info


    with closing(xbmcgui.DialogProgress()) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1="Fetching torrent information...", line2="", line3="")

        state = {"done": 0}
        def on_torrent(future):
            data = future.result()
            state["done"] += 1
            dialog.update(
                percent=int(state["done"] * 100.0 / len(torrent_nodes)),
                line2=data.get("title") or "",
            )

        with futures.ThreadPoolExecutor(max_workers=3) as pool:
            movies = []
            for node in torrent_nodes:
                info_nodes = node.findAll("td")
                a_node = first(info_nodes[0].select("div.torrentname a.plain"))
                movies.append(pool.submit(_get_torrent_info_with_meta, urljoin(BASE_URL, a_node["href"])))
            [future.add_done_callback(on_torrent) for future in movies]
            while not all(job.done() for job in movies):
                if dialog.iscanceled():
                    return
                xbmc.sleep(100)

    movies = [movie.result() for movie in movies]
    for i, movie in enumerate(movies):
        if movie.get("tmdb"):
            item = tmdb.get_list_item(movie["tmdb"])
            proper_kat_title = re.sub("\s+", " ", re.sub(r"[().-]", " ", movie["title"]))
            item["label"] = "%s (%s)" % (item["label"], re.sub(r"(?i)%s" % item["label"], "", proper_kat_title).strip())
        else:
            item = {
                "label": movie["title"],
                "info": {
                    "genre": ", ".join(movie["genres"]),
                }
            }
        lower_title = movie["title"].lower()
        if "x264" in lower_title:
            item.setdefault("stream_info", {})["codec"] = item.setdefault("info", {})["video_codec"] = "h264"
        if "xvid" in lower_title:
            item.setdefault("stream_info", {})["codec"] = item.setdefault("info", {})["video_codec"] = "xvid"
        if "720p" in lower_title:
            item.setdefault("stream_info", {}).update({
                "width": 1280,
                "height": 720,
            })
        if "1080p" in lower_title:
            item.setdefault("stream_info", {}).update({
                "width": 1920,
                "height": 1080,
            })
        item.update({
            "path": plugin.url_for("play", magnet=movie["magnet_url"]),
            "is_playable": True,
        })
        item.setdefault("info", {}).update({
            "count": i,
            "genre": "%s (S:%s P:%s)" % (item.get("info", {}).get("genre") or "", movie["seeders"], movie["leechers"]),
        })
        item.setdefault("stream_info", {}).update({
            "video": get_quality_from_name(movie["title"]),
        })
        yield item
    yield {
        "label": "Next page...",
        "path": plugin.url_for("kickass_page", root=root, page=page + 1, content_type=content_type),
    }
Ejemplo n.º 4
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
Ejemplo n.º 5
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),
            }
Ejemplo n.º 6
0
def yify_show_data(callback):
    import xbmc
    import xbmcgui
    from contextlib import nested, closing
    from itertools import izip, chain
    from multiprocessing.pool import ThreadPool
    from xbmctorrent import tmdb
    from xbmctorrent.utils import url_get_json, terminating

    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(xbmcgui.DialogProgress()) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0, line1="Fetching movie information...", line2="", line3="")

        search_result = url_get_json("%s/api/list.json" % BASE_URL, params=args, headers=HEADERS)
        movies = search_result["MovieList"]

        state = {"done": 0}
        def on_movie(data):
            state["done"] += 1
            dialog.update(
                percent=int(state["done"] * 100.0 / (len(movies) * 2)),
                line2=data.get("title") or data.get("MovieTitleClean") or "",
            )

        with nested(terminating(ThreadPool(2)), terminating(ThreadPool(2))) as (pool_yify, pool_tmdb):
            yify_list = [pool_yify.apply_async(yify_get, [movie["MovieID"]], callback=on_movie) for movie in movies]
            tmdb_list = [pool_tmdb.apply_async(tmdb.get, [movie["ImdbCode"]], callback=on_movie) for movie in movies]
            while not all(job.ready() for job in chain(yify_list, tmdb_list)):
                if dialog.iscanceled():
                    dialog.close()
                    return
                xbmc.sleep(50)

        yify_list = map(lambda job: job.get(), yify_list)
        tmdb_list = map(lambda job: job.get(), tmdb_list)
        for movie, tmdb_meta in izip(yify_list, tmdb_list):
            if tmdb_meta:
                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.url_for("play", magnet=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"]),
                    "trailer": YOUTUBE_ACTION % movie["YoutubeTrailerID"],
                    "plot_outline": movie["ShortDescription"],
                    "video_codec": "h264",
                    "mpaa": movie["AgeRating"],
                })
                width, height = map(int, movie["Resolution"].split("*"))
                item.setdefault("stream_info", {}).update({
                    "video": {
                        "codec": "h264",
                        "width": width,
                        "height": height,
                        "aspect": float(width) / float(height),
                    },
                    "audio": {
                        "codec": "aac",
                        "language": movie["Language"],
                    },
                })
                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),
            }
Ejemplo n.º 7
0
def kickass_page(root, page):
    import re
    import xbmc
    import xbmcgui
    from bs4 import BeautifulSoup
    from contextlib import closing
    from concurrent import futures
    from urlparse import urljoin
    from xbmctorrent import tmdb
    from xbmctorrent.utils import first, terminating, url_get, get_quality_from_name

    content_type = first(plugin.request.args.get("content_type")) or None
    if content_type:
        plugin.set_content(content_type)

    page = int(page)
    page_data = url_get(urljoin(BASE_URL, "%s/%d" % (root, page)))
    soup = BeautifulSoup(page_data, "html5lib")
    torrent_nodes = [
        node.parent for node in soup.findAll("td", "torrentnameCell")
    ]

    def _get_torrent_info_with_meta(url):
        torrent_info = get_torrent_info(url)
        if torrent_info["movie"] and torrent_info["imdb_id"]:
            torrent_info["tmdb"] = tmdb.get(torrent_info["imdb_id"])
        return torrent_info

    with closing(xbmcgui.DialogProgress()) as dialog:
        dialog.create(plugin.name)
        dialog.update(percent=0,
                      line1="Fetching torrent information...",
                      line2="",
                      line3="")

        state = {"done": 0}

        def on_torrent(future):
            data = future.result()
            state["done"] += 1
            dialog.update(
                percent=int(state["done"] * 100.0 / len(torrent_nodes)),
                line2=data.get("title") or "",
            )

        with futures.ThreadPoolExecutor(max_workers=3) as pool:
            movies = []
            for node in torrent_nodes:
                info_nodes = node.findAll("td")
                a_node = first(info_nodes[0].select("div.torrentname a.plain"))
                movies.append(
                    pool.submit(_get_torrent_info_with_meta,
                                urljoin(BASE_URL, a_node["href"])))
            [future.add_done_callback(on_torrent) for future in movies]
            while not all(job.done() for job in movies):
                if dialog.iscanceled():
                    return
                xbmc.sleep(100)

    movies = [movie.result() for movie in movies]
    for i, movie in enumerate(movies):
        if movie.get("tmdb"):
            item = tmdb.get_list_item(movie["tmdb"])
            proper_kat_title = re.sub("\s+", " ",
                                      re.sub(r"[().-]", " ", movie["title"]))
            item["label"] = "%s (%s)" % (item["label"],
                                         re.sub(r"(?i)%s" % item["label"], "",
                                                proper_kat_title).strip())
        else:
            item = {
                "label": movie["title"],
                "info": {
                    "genre": ", ".join(movie["genres"]),
                }
            }
        lower_title = movie["title"].lower()
        if "x264" in lower_title:
            item.setdefault("stream_info", {})["codec"] = item.setdefault(
                "info", {})["video_codec"] = "h264"
        if "xvid" in lower_title:
            item.setdefault("stream_info", {})["codec"] = item.setdefault(
                "info", {})["video_codec"] = "xvid"
        if "720p" in lower_title:
            item.setdefault("stream_info", {}).update({
                "width": 1280,
                "height": 720,
            })
        if "1080p" in lower_title:
            item.setdefault("stream_info", {}).update({
                "width": 1920,
                "height": 1080,
            })
        item.update({
            "path": plugin.url_for("play", magnet=movie["magnet_url"]),
            "is_playable": True,
        })
        item.setdefault("info", {}).update({
            "count":
            i,
            "genre":
            "%s (S:%s P:%s)" % (item.get("info", {}).get("genre")
                                or "", movie["seeders"], movie["leechers"]),
        })
        item.setdefault("stream_info", {}).update({
            "video":
            get_quality_from_name(movie["title"]),
        })
        yield item
    yield {
        "label":
        "Next page...",
        "path":
        plugin.url_for("kickass_page",
                       root=root,
                       page=page + 1,
                       content_type=content_type),
    }
Ejemplo n.º 8
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