summaryrefslogtreecommitdiff
path: root/plugin.video.redbull.tv/resources/lib/redbulltv_client.py
blob: b23075b44d65960f2c16fa1ae97b99a944d6e21c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import re, urllib2, os
import resources.lib.utils as utils

class RedbullTVClient(object):
    REDBULL_API = "https://appletv.redbull.tv/"
    ROOT_MENU = [
        {"title": "Discover", "url": REDBULL_API + "products/discover", "is_content":False},
        {"title": "TV", "url": REDBULL_API + "products/tv", "is_content":False},
        {"title": "Channels", "url": REDBULL_API + "products/channels", "is_content":False},
        {"title": "Calendar", "url": REDBULL_API + "products/calendar", "is_content":False},
        {"title": "Search", "url": REDBULL_API + "search?q=", "is_content":False},
    ]

    def __init__(self, resolution=None):
        self.resolution = resolution

    @staticmethod
    def get_resolution_code(video_resolution_id):
        return {
            "0" : "320x180",
            "1" : "426x240",
            "2" : "640x360",
            "3" : "960x540",
            "4" : "1280x720",
        }.get(video_resolution_id, "1920x1080")

    def get_stream_details(self, element):
        name = element.findtext("title")
        description = element.findtext("description")
        image = element.find("image").get("src1080")
        url = element.findtext("mediaURL")
        base_url = ''

        # Try find the specific stream based on the users preferences
        try:
            response = urllib2.urlopen(url)
            # Required to get base url in case of a redirect, to use for relative paths
            base_url = response.geturl()
            playlists = response.read()

            resolution = self.get_resolution_code(self.resolution)
            media_url = re.search(
                "RESOLUTION=" + resolution + ".*\n(.*)",
                playlists).group(1)
        except Exception:
            pass
        else:
            url = media_url

        # if url is relative, add the base path
        if base_url != '' and not url.startswith('http'):
            url = os.path.dirname(base_url) + '/' + url

        return {"title":name, "url":url, "summary":description, "image": image, "is_stream":True}

    def get_element_details(self, element, url=None):
        details = {"url":url, "is_content":False}
        subtitle = element.findtext('.//subtitle') or element.findtext('.//label2') or ""
        details["title"] = (element.get("accessibilityLabel") or element.findtext('.//label')) + ((" - " + subtitle) if subtitle else "")
        details["summary"] = element.findtext('.//summary')
        details["image"] = element.find('.//image').get('src1080') if element.find('.//image') is not None else None
        details["event_date"] = element.findtext('.//rightLabel')

        # Get url of item, or name of selected category
        if "onSelect" in element.attrib:
            details["url"] = utils.strip_url(element.get("onSelect"))
            details["is_content"] = re.search(self.REDBULL_API + "(content|linear_stream)", details["url"]) is not None
        elif not details["event_date"]:
            details["category"] = details["title"]

        # Strip out any keys with empty values
        return {k:v for k, v in details.iteritems() if v is not None}

    def get_items(self, url=None, category=None):
        # If no url is specified, return the root menu
        if url is None:
            return self.ROOT_MENU

        xml = utils.get_xml(url)
        items = []

        # if the current url is a media stream
        if xml.find('.//httpLiveStreamingVideoAsset') is not None:
            items.append(self.get_stream_details(xml.find('.//httpLiveStreamingVideoAsset')))
        # if no category is specified, find the categories or item collection
        elif category is None:
            data = {
                "collectionDividers": xml.findall('.//collectionDivider'),
            }
            # Show Categories if relevant
            if data["collectionDividers"]:
                items += self.generate_items(
                    xml.findall('.//showcase') +
                    data["collectionDividers"],
                    url)
            else:
                items += self.generate_items(
                    xml.findall('.//twoLineMenuItem') +
                    xml.findall('.//twoLineEnhancedMenuItem') +
                    xml.findall('.//sixteenByNinePoster') +
                    xml.findall('.//actionButton'),
                    url)
        # if a category is specified, find the items for the specified category
        elif category is not None:
            if category == 'Featured':
                items += self.generate_items(xml.findall('.//showcasePoster'))
            else:
                collections = xml.iterfind(".//collectionDivider/../*")
                for collection in collections:
                    if collection.tag == 'collectionDivider' and collection.get("accessibilityLabel") == category:
                        items += self.generate_items(collections.next().find('.//items').getchildren())

        return items

    def generate_items(self, xml_elements, url=None):
        items = []
        for item in xml_elements:
            items.append(self.get_element_details(item, url))
        return items