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 streamajoker.utils import SafeDialogProgress, get_quality_from_name, get_show_info_from_name, normalize_release_tags
    from streamajoker 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
def check_episode_data(item):
    from streamajoker.utils import get_show_info_from_name
    show_info = get_quality_from_name(item["title"])
    if not show_info:
        return