]>
code.delx.au - webdl/blob - sbs.py
2 from common
import grab_html
, grab_json
, grab_xml
, download_hls
, 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_SMIL_URL
= BASE
+ "/api/v3/video_smil?id="
14 "smil": "http://www.w3.org/2005/SMIL21/Language",
18 class SbsVideoNode(Node
):
19 def __init__(self
, title
, parent
, url
):
20 Node
.__init
__(self
, title
, parent
)
21 self
.video_id
= url
.split("/")[-1]
22 self
.can_download
= True
25 filename
= self
.title
+ ".ts"
27 with requests_cache
.disabled():
28 doc
= grab_xml(VIDEO_SMIL_URL
+ self
.video_id
)
29 video_el
= doc
.xpath("//smil:video", namespaces
=NS
)
31 print("Cannot find video:", error
)
33 video_url
= video_el
[0].attrib
["src"]
35 return download_hls(filename
, video_url
)
37 class SbsNavNode(Node
):
38 def create_video_node(self
, entry_data
):
39 SbsVideoNode(entry_data
["title"], self
, entry_data
["id"])
41 def find_existing_child(self
, path
):
42 for child
in self
.children
:
43 if child
.title
== path
:
46 class SbsRootNode(SbsNavNode
):
47 def __init__(self
, parent
):
48 Node
.__init
__(self
, "SBS", parent
)
50 def fill_children(self
):
51 all_video_entries
= self
.load_all_video_entries()
52 category_and_entry_data
= self
.explode_videos_to_unique_categories(all_video_entries
)
53 for category_path
, entry_data
in category_and_entry_data
:
54 nav_node
= self
.create_nav_node(self
, category_path
)
55 nav_node
.create_video_node(entry_data
)
57 def load_all_video_entries(self
):
62 "Channel/SBS VICELAND",
63 "Channel/SBS World Movies",
64 "Channel/Web Exclusive",
68 for channel
in channels
:
69 self
.load_all_video_entries_for_channel(all_entries
, channel
)
71 all_entries
= list(all_entries
.values())
72 print(" SBS fetched", len(all_entries
))
75 def load_all_video_entries_for_channel(self
, all_entries
, channel
):
78 duplicate_warning
= False
81 entries
= self
.fetch_entries_page(channel
, offset
, page_size
)
87 if guid
in entries
and not duplicate_warning
:
88 # https://bitbucket.org/delx/webdl/issues/102/recent-sbs-series-missing
89 logging
.warn("SBS returned a duplicate response, data is probably missing. Try decreasing page_size.")
90 duplicate_warning
= True
92 all_entries
[guid
] = entry
95 if os
.isatty(sys
.stdout
.fileno()):
99 def fetch_entries_page(self
, channel
, offset
, page_size
):
100 url
= append_to_qs(FULL_VIDEO_LIST
, {
101 "range": "%s-%s" % (offset
, offset
+page_size
-1),
102 "byCategories": channel
,
104 data
= grab_json(url
)
105 if "entries" not in data
:
106 raise Exception("Missing data in SBS response", data
)
107 return data
["entries"]
109 def explode_videos_to_unique_categories(self
, all_video_entries
):
110 for entry_data
in all_video_entries
:
111 for category_data
in entry_data
["media$categories"]:
112 category_path
= self
.calculate_category_path(
113 category_data
["media$scheme"],
114 category_data
["media$name"],
117 yield category_path
, entry_data
119 def calculate_category_path(self
, scheme
, name
):
124 name
= name
.split("/")
125 if name
[0] != scheme
:
126 name
.insert(0, scheme
)
129 def create_nav_node(self
, parent
, category_path
):
130 if not category_path
:
133 current_path
= category_path
[0]
134 current_node
= parent
.find_existing_child(current_path
)
136 current_node
= SbsNavNode(current_path
, parent
)
137 return self
.create_nav_node(current_node
, category_path
[1:])
139 def fill_nodes(root_node
):
140 SbsRootNode(root_node
)