]>
Commit | Line | Data |
---|---|---|
6e7dfe49 C |
1 | from __future__ import unicode_literals |
2 | ||
3 | import json | |
4 | ||
5 | from .common import InfoExtractor | |
6 | from ..utils import ( | |
7 | try_get, | |
8 | int_or_none, | |
9 | url_or_none, | |
10 | float_or_none, | |
11 | unified_timestamp, | |
12 | ) | |
13 | ||
14 | ||
15 | class BannedVideoIE(InfoExtractor): | |
16 | _VALID_URL = r'https?://(?:www\.)?banned\.video/watch\?id=(?P<id>[0-f]{24})' | |
17 | _TESTS = [{ | |
18 | 'url': 'https://banned.video/watch?id=5e7a859644e02200c6ef5f11', | |
19 | 'md5': '14b6e81d41beaaee2215cd75c6ed56e4', | |
20 | 'info_dict': { | |
21 | 'id': '5e7a859644e02200c6ef5f11', | |
22 | 'ext': 'mp4', | |
23 | 'title': 'China Discovers Origin of Corona Virus: Issues Emergency Statement', | |
24 | 'thumbnail': r're:^https?://(?:www\.)?assets\.infowarsmedia.com/images/', | |
25 | 'description': 'md5:560d96f02abbebe6c6b78b47465f6b28', | |
26 | 'upload_date': '20200324', | |
27 | 'timestamp': 1585087895, | |
28 | } | |
29 | }] | |
30 | ||
31 | _GRAPHQL_GETMETADATA_QUERY = ''' | |
32 | query GetVideoAndComments($id: String!) { | |
33 | getVideo(id: $id) { | |
34 | streamUrl | |
35 | directUrl | |
36 | unlisted | |
37 | live | |
38 | tags { | |
39 | name | |
40 | } | |
41 | title | |
42 | summary | |
43 | playCount | |
44 | largeImage | |
45 | videoDuration | |
46 | channel { | |
47 | _id | |
48 | title | |
49 | } | |
50 | createdAt | |
51 | } | |
52 | getVideoComments(id: $id, limit: 999999, offset: 0) { | |
53 | _id | |
54 | content | |
55 | user { | |
56 | _id | |
57 | username | |
58 | } | |
59 | voteCount { | |
60 | positive | |
61 | } | |
62 | createdAt | |
63 | replyCount | |
64 | } | |
65 | }''' | |
66 | ||
67 | _GRAPHQL_GETCOMMENTSREPLIES_QUERY = ''' | |
68 | query GetCommentReplies($id: String!) { | |
69 | getCommentReplies(id: $id, limit: 999999, offset: 0) { | |
70 | _id | |
71 | content | |
72 | user { | |
73 | _id | |
74 | username | |
75 | } | |
76 | voteCount { | |
77 | positive | |
78 | } | |
79 | createdAt | |
80 | replyCount | |
81 | } | |
82 | }''' | |
83 | ||
84 | _GRAPHQL_QUERIES = { | |
85 | 'GetVideoAndComments': _GRAPHQL_GETMETADATA_QUERY, | |
86 | 'GetCommentReplies': _GRAPHQL_GETCOMMENTSREPLIES_QUERY, | |
87 | } | |
88 | ||
89 | def _call_api(self, video_id, id, operation, note): | |
90 | return self._download_json( | |
91 | 'https://api.infowarsmedia.com/graphql', video_id, note=note, | |
92 | headers={ | |
93 | 'Content-Type': 'application/json; charset=utf-8' | |
94 | }, data=json.dumps({ | |
95 | 'variables': {'id': id}, | |
96 | 'operationName': operation, | |
97 | 'query': self._GRAPHQL_QUERIES[operation] | |
98 | }).encode('utf8')).get('data') | |
99 | ||
100 | def _extract_comments(self, video_id, comments, comment_data): | |
101 | for comment in comment_data.copy(): | |
102 | comment_id = comment.get('_id') | |
103 | if comment.get('replyCount') > 0: | |
104 | reply_json = self._call_api( | |
105 | video_id, comment_id, 'GetCommentReplies', | |
106 | f'Downloading replies for comment {comment_id}') | |
107 | comments.extend( | |
108 | self._parse_comment(reply, comment_id) | |
109 | for reply in reply_json.get('getCommentReplies')) | |
110 | ||
111 | return { | |
112 | 'comments': comments, | |
113 | 'comment_count': len(comments), | |
114 | } | |
115 | ||
116 | @staticmethod | |
117 | def _parse_comment(comment_data, parent): | |
118 | return { | |
119 | 'id': comment_data.get('_id'), | |
120 | 'text': comment_data.get('content'), | |
121 | 'author': try_get(comment_data, lambda x: x['user']['username']), | |
122 | 'author_id': try_get(comment_data, lambda x: x['user']['_id']), | |
123 | 'timestamp': unified_timestamp(comment_data.get('createdAt')), | |
124 | 'parent': parent, | |
125 | 'like_count': try_get(comment_data, lambda x: x['voteCount']['positive']), | |
126 | } | |
127 | ||
128 | def _real_extract(self, url): | |
129 | video_id = self._match_id(url) | |
130 | video_json = self._call_api(video_id, video_id, 'GetVideoAndComments', 'Downloading video metadata') | |
131 | video_info = video_json['getVideo'] | |
132 | is_live = video_info.get('live') | |
133 | comments = [self._parse_comment(comment, 'root') for comment in video_json.get('getVideoComments')] | |
134 | ||
135 | formats = [{ | |
136 | 'format_id': 'direct', | |
137 | 'quality': 1, | |
138 | 'url': video_info.get('directUrl'), | |
139 | 'ext': 'mp4', | |
140 | }] if url_or_none(video_info.get('directUrl')) else [] | |
141 | if video_info.get('streamUrl'): | |
142 | formats.extend(self._extract_m3u8_formats( | |
143 | video_info.get('streamUrl'), video_id, 'mp4', | |
144 | entry_protocol='m3u8_native', m3u8_id='hls', live=True)) | |
145 | self._sort_formats(formats) | |
146 | ||
147 | return { | |
148 | 'id': video_id, | |
149 | 'title': video_info.get('title')[:-1], | |
150 | 'formats': formats, | |
151 | 'is_live': is_live, | |
152 | 'description': video_info.get('summary'), | |
153 | 'channel': try_get(video_info, lambda x: x['channel']['title']), | |
154 | 'channel_id': try_get(video_info, lambda x: x['channel']['_id']), | |
155 | 'view_count': int_or_none(video_info.get('playCount')), | |
156 | 'thumbnail': url_or_none(video_info.get('largeImage')), | |
157 | 'duration': float_or_none(video_info.get('videoDuration')), | |
158 | 'timestamp': unified_timestamp(video_info.get('createdAt')), | |
159 | 'tags': [tag.get('name') for tag in video_info.get('tags')], | |
160 | 'availability': self._availability(is_unlisted=video_info.get('unlisted')), | |
161 | 'comments': comments, | |
162 | '__post_extractor': ( | |
163 | (lambda: self._extract_comments(video_id, comments, video_json.get('getVideoComments'))) | |
164 | if self.get_param('getcomments') else None) | |
165 | } |