]>
code.delx.au - webdl/blob - sbs.py
2 from common
import grab_html
, grab_json
, grab_xml
, download_hls
, download_mpd
, Node
, append_to_qs
9 BASE
= "https://www.sbs.com.au"
10 FULL_VIDEO_LIST
= BASE
+ "/api/video_feed/f/Bgtm9B/sbs-section-programs/"
11 VIDEO_URL
= BASE
+ "/ondemand/video/single/%s"
12 PARAMS_URL
= BASE
+ "/api/video_pdkvars/id/%s?form=json"
15 "smil": "http://www.w3.org/2005/SMIL21/Language",
19 class SbsVideoNode(Node
):
20 def __init__(self
, title
, parent
, url
):
21 Node
.__init
__(self
, title
, parent
)
22 self
.video_id
= url
.split("/")[-1]
23 self
.can_download
= True
26 with requests_cache
.disabled():
27 doc
= grab_html(VIDEO_URL
% self
.video_id
)
28 player_params
= grab_json(PARAMS_URL
% self
.video_id
)
30 error
= player_params
.get("error", None)
32 print("Cannot download:", error
)
35 release_url
= player_params
["releaseUrls"]["html"]
36 filename
= self
.title
+ ".ts"
38 hls_url
= self
.get_hls_url(release_url
)
40 return download_hls(filename
, hls_url
)
42 return download_mpd(filename
, release_url
)
44 def get_hls_url(self
, release_url
):
45 with requests_cache
.disabled():
46 doc
= grab_xml("https:" + release_url
.replace("http:", "").replace("https:", ""))
47 video
= doc
.xpath("//smil:video", namespaces
=NS
)
50 video_url
= video
[0].attrib
["src"]
53 class SbsNavNode(Node
):
54 def create_video_node(self
, entry_data
):
55 SbsVideoNode(entry_data
["title"], self
, entry_data
["id"])
57 def find_existing_child(self
, path
):
58 for child
in self
.children
:
59 if child
.title
== path
:
62 class SbsRootNode(SbsNavNode
):
63 def __init__(self
, parent
):
64 Node
.__init
__(self
, "SBS", parent
)
66 def fill_children(self
):
67 all_video_entries
= self
.load_all_video_entries()
68 category_and_entry_data
= self
.explode_videos_to_unique_categories(all_video_entries
)
69 for category_path
, entry_data
in category_and_entry_data
:
70 nav_node
= self
.create_nav_node(self
, category_path
)
71 nav_node
.create_video_node(entry_data
)
73 def load_all_video_entries(self
):
77 "Channel/SBS VICELAND",
78 "Channel/SBS World Movies",
79 "Channel/Web Exclusive",
83 for channel
in channels
:
84 self
.load_all_video_entries_for_channel(all_entries
, channel
)
86 all_entries
= list(all_entries
.values())
87 print(" SBS fetched", len(all_entries
))
90 def load_all_video_entries_for_channel(self
, all_entries
, channel
):
93 duplicate_warning
= False
96 entries
= self
.fetch_entries_page(channel
, offset
, page_size
)
100 for entry
in entries
:
102 if guid
in entries
and not duplicate_warning
:
103 # https://bitbucket.org/delx/webdl/issues/102/recent-sbs-series-missing
104 logging
.warn("SBS returned a duplicate response, data is probably missing. Try decreasing page_size.")
105 duplicate_warning
= True
107 all_entries
[guid
] = entry
110 if os
.isatty(sys
.stdout
.fileno()):
111 sys
.stdout
.write(".")
114 def fetch_entries_page(self
, channel
, offset
, page_size
):
115 url
= append_to_qs(FULL_VIDEO_LIST
, {
116 "range": "%s-%s" % (offset
, offset
+page_size
-1),
117 "byCategories": channel
,
119 data
= grab_json(url
)
120 if "entries" not in data
:
121 raise Exception("Missing data in SBS response", data
)
122 return data
["entries"]
124 def explode_videos_to_unique_categories(self
, all_video_entries
):
125 for entry_data
in all_video_entries
:
126 for category_data
in entry_data
["media$categories"]:
127 category_path
= self
.calculate_category_path(
128 category_data
["media$scheme"],
129 category_data
["media$name"],
132 yield category_path
, entry_data
134 def calculate_category_path(self
, scheme
, name
):
139 name
= name
.split("/")
140 if name
[0] != scheme
:
141 name
.insert(0, scheme
)
144 def create_nav_node(self
, parent
, category_path
):
145 if not category_path
:
148 current_path
= category_path
[0]
149 current_node
= parent
.find_existing_child(current_path
)
151 current_node
= SbsNavNode(current_path
, parent
)
152 return self
.create_nav_node(current_node
, category_path
[1:])
154 def fill_nodes(root_node
):
155 SbsRootNode(root_node
)