]>
code.delx.au - webdl/blob - iview.py
1 from common
import grab_json
, grab_xml
, Node
, download_hls
6 API_URL
= "https://iview.abc.net.au/api"
7 AUTH_URL
= "https://iview.abc.net.au/auth"
9 def format_episode_title(series
, ep
):
11 return series
+ " " + ep
15 def add_episode(parent
, ep_info
):
16 video_key
= ep_info
["episodeHouseNumber"]
17 series_title
= ep_info
["seriesTitle"]
18 title
= ep_info
.get("title", None)
19 episode_title
= format_episode_title(series_title
, title
)
21 IviewEpisodeNode(episode_title
, parent
, video_key
)
23 class IviewEpisodeNode(Node
):
24 def __init__(self
, title
, parent
, video_key
):
25 Node
.__init
__(self
, title
, parent
)
26 self
.video_key
= video_key
27 self
.filename
= title
+ ".ts"
28 self
.can_download
= True
30 def find_hls_url(self
, playlist
):
31 for video
in playlist
:
32 if video
["type"] == "program":
33 for quality
in ["hls-plus", "hls-high"]:
35 return video
[quality
].replace("http:", "https:")
36 raise Exception("Missing program stream for " + self
.video_key
)
38 def get_auth_details(self
):
39 with requests_cache
.disabled():
40 auth_doc
= grab_xml(AUTH_URL
)
42 "auth": "http://www.abc.net.au/iView/Services/iViewHandshaker",
44 token
= auth_doc
.xpath("//auth:tokenhd/text()", namespaces
=NS
)[0]
45 token_url
= auth_doc
.xpath("//auth:server/text()", namespaces
=NS
)[0]
46 token_hostname
= urllib
.parse
.urlparse(token_url
).netloc
47 return token
, token_hostname
49 def add_auth_token_to_url(self
, video_url
, token
, token_hostname
):
50 parsed_url
= urllib
.parse
.urlparse(video_url
)
51 hacked_url
= parsed_url
._replace
(netloc
=token_hostname
, query
="hdnea=" + token
)
52 video_url
= urllib
.parse
.urlunparse(hacked_url
)
56 info
= grab_json(API_URL
+ "/programs/" + self
.video_key
)
57 if "playlist" not in info
:
59 video_url
= self
.find_hls_url(info
["playlist"])
60 token
, token_hostname
= self
.get_auth_details()
61 video_url
= self
.add_auth_token_to_url(video_url
, token
, token_hostname
)
62 return download_hls(self
.filename
, video_url
)
64 class IviewIndexNode(Node
):
65 def __init__(self
, title
, parent
, url
):
66 Node
.__init
__(self
, title
, parent
)
68 self
.unique_series
= set()
70 def fill_children(self
):
71 info
= grab_json(self
.url
)
72 for key
in ["carousels", "collections", "index"]:
73 for collection_list
in info
.get(key
, None):
74 if isinstance(collection_list
, dict):
75 for ep_info
in collection_list
.get("episodes", []):
76 self
.add_series(ep_info
)
78 def add_series(self
, ep_info
):
79 title
= ep_info
["seriesTitle"]
80 if title
in self
.unique_series
:
82 self
.unique_series
.add(title
)
83 url
= API_URL
+ "/" + ep_info
["href"]
84 IviewSeriesNode(title
, self
, url
)
86 class IviewSeriesNode(Node
):
87 def __init__(self
, title
, parent
, url
):
88 Node
.__init
__(self
, title
, parent
)
91 def fill_children(self
):
92 ep_info
= grab_json(self
.url
)
93 series_slug
= ep_info
["href"].split("/")[1]
94 series_url
= API_URL
+ "/series/" + series_slug
+ "/" + ep_info
["seriesHouseNumber"]
95 info
= grab_json(series_url
)
96 for ep_info
in info
.get("episodes", []):
97 add_episode(self
, ep_info
)
99 class IviewFlatNode(Node
):
100 def __init__(self
, title
, parent
, url
):
101 Node
.__init
__(self
, title
, parent
)
104 def fill_children(self
):
105 info
= grab_json(self
.url
)
107 add_episode(self
, ep_info
)
110 class IviewRootNode(Node
):
111 def load_categories(self
):
112 by_category_node
= Node("By Category", self
)
114 data
= grab_json(API_URL
+ "/categories")
115 categories
= data
["categories"]
117 for category_data
in categories
:
118 category_title
= category_data
["title"]
119 category_title
= string
.capwords(category_title
)
121 category_href
= category_data
["href"]
123 IviewIndexNode(category_title
, by_category_node
, API_URL
+ "/" + category_href
)
125 def load_channels(self
):
126 by_channel_node
= Node("By Channel", self
)
128 data
= grab_json(API_URL
+ "/channel")
129 channels
= data
["channels"]
131 for channel_data
in channels
:
132 channel_id
= channel_data
["categoryID"]
137 "abc4kids": "ABC4Kids",
139 "abcarts": "ABC Arts",
140 }.get(channel_id
, channel_data
["title"])
142 channel_href
= channel_data
["href"]
144 IviewIndexNode(channel_title
, by_channel_node
, API_URL
+ "/" + channel_href
)
146 def load_featured(self
):
147 IviewFlatNode("Featured", self
, API_URL
+ "/featured")
149 def fill_children(self
):
150 self
.load_categories()
155 def fill_nodes(root_node
):
156 IviewRootNode("ABC iView", root_node
)