You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

601 line
27KB

  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..compat import compat_str
  6. from ..utils import (
  7. int_or_none,
  8. parse_resolution,
  9. str_or_none,
  10. try_get,
  11. unified_timestamp,
  12. url_or_none,
  13. urljoin,
  14. )
  15. class PeerTubeIE(InfoExtractor):
  16. _INSTANCES_RE = r'''(?:
  17. # Taken from https://instances.joinpeertube.org/instances
  18. peertube\.rainbowswingers\.net|
  19. tube\.stanisic\.nl|
  20. peer\.suiri\.us|
  21. medias\.libox\.fr|
  22. videomensoif\.ynh\.fr|
  23. peertube\.travelpandas\.eu|
  24. peertube\.rachetjay\.fr|
  25. peertube\.montecsys\.fr|
  26. tube\.eskuero\.me|
  27. peer\.tube|
  28. peertube\.umeahackerspace\.se|
  29. tube\.nx-pod\.de|
  30. video\.monsieurbidouille\.fr|
  31. tube\.openalgeria\.org|
  32. vid\.lelux\.fi|
  33. video\.anormallostpod\.ovh|
  34. tube\.crapaud-fou\.org|
  35. peertube\.stemy\.me|
  36. lostpod\.space|
  37. exode\.me|
  38. peertube\.snargol\.com|
  39. vis\.ion\.ovh|
  40. videosdulib\.re|
  41. v\.mbius\.io|
  42. videos\.judrey\.eu|
  43. peertube\.osureplayviewer\.xyz|
  44. peertube\.mathieufamily\.ovh|
  45. www\.videos-libr\.es|
  46. fightforinfo\.com|
  47. peertube\.fediverse\.ru|
  48. peertube\.oiseauroch\.fr|
  49. video\.nesven\.eu|
  50. v\.bearvideo\.win|
  51. video\.qoto\.org|
  52. justporn\.cc|
  53. video\.vny\.fr|
  54. peervideo\.club|
  55. tube\.taker\.fr|
  56. peertube\.chantierlibre\.org|
  57. tube\.ipfixe\.info|
  58. tube\.kicou\.info|
  59. tube\.dodsorf\.as|
  60. videobit\.cc|
  61. video\.yukari\.moe|
  62. videos\.elbinario\.net|
  63. hkvideo\.live|
  64. pt\.tux\.tf|
  65. www\.hkvideo\.live|
  66. FIGHTFORINFO\.com|
  67. pt\.765racing\.com|
  68. peertube\.gnumeria\.eu\.org|
  69. nordenmedia\.com|
  70. peertube\.co\.uk|
  71. tube\.darfweb\.eu|
  72. tube\.kalah-france\.org|
  73. 0ch\.in|
  74. vod\.mochi\.academy|
  75. film\.node9\.org|
  76. peertube\.hatthieves\.es|
  77. video\.fitchfamily\.org|
  78. peertube\.ddns\.net|
  79. video\.ifuncle\.kr|
  80. video\.fdlibre\.eu|
  81. tube\.22decembre\.eu|
  82. peertube\.harmoniescreatives\.com|
  83. tube\.fabrigli\.fr|
  84. video\.thedwyers\.co|
  85. video\.bruitbruit\.com|
  86. peertube\.foxfam\.club|
  87. peer\.philoxweb\.be|
  88. videos\.bugs\.social|
  89. peertube\.malbert\.xyz|
  90. peertube\.bilange\.ca|
  91. libretube\.net|
  92. diytelevision\.com|
  93. peertube\.fedilab\.app|
  94. libre\.video|
  95. video\.mstddntfdn\.online|
  96. us\.tv|
  97. peertube\.sl-network\.fr|
  98. peertube\.dynlinux\.io|
  99. peertube\.david\.durieux\.family|
  100. peertube\.linuxrocks\.online|
  101. peerwatch\.xyz|
  102. v\.kretschmann\.social|
  103. tube\.otter\.sh|
  104. yt\.is\.nota\.live|
  105. tube\.dragonpsi\.xyz|
  106. peertube\.boneheadmedia\.com|
  107. videos\.funkwhale\.audio|
  108. watch\.44con\.com|
  109. peertube\.gcaillaut\.fr|
  110. peertube\.icu|
  111. pony\.tube|
  112. spacepub\.space|
  113. tube\.stbr\.io|
  114. v\.mom-gay\.faith|
  115. tube\.port0\.xyz|
  116. peertube\.simounet\.net|
  117. play\.jergefelt\.se|
  118. peertube\.zeteo\.me|
  119. tube\.danq\.me|
  120. peertube\.kerenon\.com|
  121. tube\.fab-l3\.org|
  122. tube\.calculate\.social|
  123. peertube\.mckillop\.org|
  124. tube\.netzspielplatz\.de|
  125. vod\.ksite\.de|
  126. peertube\.laas\.fr|
  127. tube\.govital\.net|
  128. peertube\.stephenson\.cc|
  129. bistule\.nohost\.me|
  130. peertube\.kajalinifi\.de|
  131. video\.ploud\.jp|
  132. video\.omniatv\.com|
  133. peertube\.ffs2play\.fr|
  134. peertube\.leboulaire\.ovh|
  135. peertube\.tronic-studio\.com|
  136. peertube\.public\.cat|
  137. peertube\.metalbanana\.net|
  138. video\.1000i100\.fr|
  139. peertube\.alter-nativ-voll\.de|
  140. tube\.pasa\.tf|
  141. tube\.worldofhauru\.xyz|
  142. pt\.kamp\.site|
  143. peertube\.teleassist\.fr|
  144. videos\.mleduc\.xyz|
  145. conf\.tube|
  146. media\.privacyinternational\.org|
  147. pt\.forty-two\.nl|
  148. video\.halle-leaks\.de|
  149. video\.grosskopfgames\.de|
  150. peertube\.schaeferit\.de|
  151. peertube\.jackbot\.fr|
  152. tube\.extinctionrebellion\.fr|
  153. peertube\.f-si\.org|
  154. video\.subak\.ovh|
  155. videos\.koweb\.fr|
  156. peertube\.zergy\.net|
  157. peertube\.roflcopter\.fr|
  158. peertube\.floss-marketing-school\.com|
  159. vloggers\.social|
  160. peertube\.iriseden\.eu|
  161. videos\.ubuntu-paris\.org|
  162. peertube\.mastodon\.host|
  163. armstube\.com|
  164. peertube\.s2s\.video|
  165. peertube\.lol|
  166. tube\.open-plug\.eu|
  167. open\.tube|
  168. peertube\.ch|
  169. peertube\.normandie-libre\.fr|
  170. peertube\.slat\.org|
  171. video\.lacaveatonton\.ovh|
  172. peertube\.uno|
  173. peertube\.servebeer\.com|
  174. peertube\.fedi\.quebec|
  175. tube\.h3z\.jp|
  176. tube\.plus200\.com|
  177. peertube\.eric\.ovh|
  178. tube\.metadocs\.cc|
  179. tube\.unmondemeilleur\.eu|
  180. gouttedeau\.space|
  181. video\.antirep\.net|
  182. nrop\.cant\.at|
  183. tube\.ksl-bmx\.de|
  184. tube\.plaf\.fr|
  185. tube\.tchncs\.de|
  186. video\.devinberg\.com|
  187. hitchtube\.fr|
  188. peertube\.kosebamse\.com|
  189. yunopeertube\.myddns\.me|
  190. peertube\.varney\.fr|
  191. peertube\.anon-kenkai\.com|
  192. tube\.maiti\.info|
  193. tubee\.fr|
  194. videos\.dinofly\.com|
  195. toobnix\.org|
  196. videotape\.me|
  197. voca\.tube|
  198. video\.heromuster\.com|
  199. video\.lemediatv\.fr|
  200. video\.up\.edu\.ph|
  201. balafon\.video|
  202. video\.ivel\.fr|
  203. thickrips\.cloud|
  204. pt\.laurentkruger\.fr|
  205. video\.monarch-pass\.net|
  206. peertube\.artica\.center|
  207. video\.alternanet\.fr|
  208. indymotion\.fr|
  209. fanvid\.stopthatimp\.net|
  210. video\.farci\.org|
  211. v\.lesterpig\.com|
  212. video\.okaris\.de|
  213. tube\.pawelko\.net|
  214. peertube\.mablr\.org|
  215. tube\.fede\.re|
  216. pytu\.be|
  217. evertron\.tv|
  218. devtube\.dev-wiki\.de|
  219. raptube\.antipub\.org|
  220. video\.selea\.se|
  221. peertube\.mygaia\.org|
  222. video\.oh14\.de|
  223. peertube\.livingutopia\.org|
  224. peertube\.the-penguin\.de|
  225. tube\.thechangebook\.org|
  226. tube\.anjara\.eu|
  227. pt\.pube\.tk|
  228. video\.samedi\.pm|
  229. mplayer\.demouliere\.eu|
  230. widemus\.de|
  231. peertube\.me|
  232. peertube\.zapashcanon\.fr|
  233. video\.latavernedejohnjohn\.fr|
  234. peertube\.pcservice46\.fr|
  235. peertube\.mazzonetto\.eu|
  236. video\.irem\.univ-paris-diderot\.fr|
  237. video\.livecchi\.cloud|
  238. alttube\.fr|
  239. video\.coop\.tools|
  240. video\.cabane-libre\.org|
  241. peertube\.openstreetmap\.fr|
  242. videos\.alolise\.org|
  243. irrsinn\.video|
  244. video\.antopie\.org|
  245. scitech\.video|
  246. tube2\.nemsia\.org|
  247. video\.amic37\.fr|
  248. peertube\.freeforge\.eu|
  249. video\.arbitrarion\.com|
  250. video\.datsemultimedia\.com|
  251. stoptrackingus\.tv|
  252. peertube\.ricostrongxxx\.com|
  253. docker\.videos\.lecygnenoir\.info|
  254. peertube\.togart\.de|
  255. tube\.postblue\.info|
  256. videos\.domainepublic\.net|
  257. peertube\.cyber-tribal\.com|
  258. video\.gresille\.org|
  259. peertube\.dsmouse\.net|
  260. cinema\.yunohost\.support|
  261. tube\.theocevaer\.fr|
  262. repro\.video|
  263. tube\.4aem\.com|
  264. quaziinc\.com|
  265. peertube\.metawurst\.space|
  266. videos\.wakapo\.com|
  267. video\.ploud\.fr|
  268. video\.freeradical\.zone|
  269. tube\.valinor\.fr|
  270. refuznik\.video|
  271. pt\.kircheneuenburg\.de|
  272. peertube\.asrun\.eu|
  273. peertube\.lagob\.fr|
  274. videos\.side-ways\.net|
  275. 91video\.online|
  276. video\.valme\.io|
  277. video\.taboulisme\.com|
  278. videos-libr\.es|
  279. tv\.mooh\.fr|
  280. nuage\.acostey\.fr|
  281. video\.monsieur-a\.fr|
  282. peertube\.librelois\.fr|
  283. videos\.pair2jeux\.tube|
  284. videos\.pueseso\.club|
  285. peer\.mathdacloud\.ovh|
  286. media\.assassinate-you\.net|
  287. vidcommons\.org|
  288. ptube\.rousset\.nom\.fr|
  289. tube\.cyano\.at|
  290. videos\.squat\.net|
  291. video\.iphodase\.fr|
  292. peertube\.makotoworkshop\.org|
  293. peertube\.serveur\.slv-valbonne\.fr|
  294. vault\.mle\.party|
  295. hostyour\.tv|
  296. videos\.hack2g2\.fr|
  297. libre\.tube|
  298. pire\.artisanlogiciel\.net|
  299. videos\.numerique-en-commun\.fr|
  300. video\.netsyms\.com|
  301. video\.die-partei\.social|
  302. video\.writeas\.org|
  303. peertube\.swarm\.solvingmaz\.es|
  304. tube\.pericoloso\.ovh|
  305. watching\.cypherpunk\.observer|
  306. videos\.adhocmusic\.com|
  307. tube\.rfc1149\.net|
  308. peertube\.librelabucm\.org|
  309. videos\.numericoop\.fr|
  310. peertube\.koehn\.com|
  311. peertube\.anarchmusicall\.net|
  312. tube\.kampftoast\.de|
  313. vid\.y-y\.li|
  314. peertube\.xtenz\.xyz|
  315. diode\.zone|
  316. tube\.egf\.mn|
  317. peertube\.nomagic\.uk|
  318. visionon\.tv|
  319. videos\.koumoul\.com|
  320. video\.rastapuls\.com|
  321. video\.mantlepro\.com|
  322. video\.deadsuperhero\.com|
  323. peertube\.musicstudio\.pro|
  324. peertube\.we-keys\.fr|
  325. artitube\.artifaille\.fr|
  326. peertube\.ethernia\.net|
  327. tube\.midov\.pl|
  328. peertube\.fr|
  329. watch\.snoot\.tube|
  330. peertube\.donnadieu\.fr|
  331. argos\.aquilenet\.fr|
  332. tube\.nemsia\.org|
  333. tube\.bruniau\.net|
  334. videos\.darckoune\.moe|
  335. tube\.traydent\.info|
  336. dev\.videos\.lecygnenoir\.info|
  337. peertube\.nayya\.org|
  338. peertube\.live|
  339. peertube\.mofgao\.space|
  340. video\.lequerrec\.eu|
  341. peertube\.amicale\.net|
  342. aperi\.tube|
  343. tube\.ac-lyon\.fr|
  344. video\.lw1\.at|
  345. www\.yiny\.org|
  346. videos\.pofilo\.fr|
  347. tube\.lou\.lt|
  348. choob\.h\.etbus\.ch|
  349. tube\.hoga\.fr|
  350. peertube\.heberge\.fr|
  351. video\.obermui\.de|
  352. videos\.cloudfrancois\.fr|
  353. betamax\.video|
  354. video\.typica\.us|
  355. tube\.piweb\.be|
  356. video\.blender\.org|
  357. peertube\.cat|
  358. tube\.kdy\.ch|
  359. pe\.ertu\.be|
  360. peertube\.social|
  361. videos\.lescommuns\.org|
  362. tv\.datamol\.org|
  363. videonaute\.fr|
  364. dialup\.express|
  365. peertube\.nogafa\.org|
  366. megatube\.lilomoino\.fr|
  367. peertube\.tamanoir\.foucry\.net|
  368. peertube\.devosi\.org|
  369. peertube\.1312\.media|
  370. tube\.bootlicker\.party|
  371. skeptikon\.fr|
  372. video\.blueline\.mg|
  373. tube\.homecomputing\.fr|
  374. tube\.ouahpiti\.info|
  375. video\.tedomum\.net|
  376. video\.g3l\.org|
  377. fontube\.fr|
  378. peertube\.gaialabs\.ch|
  379. tube\.kher\.nl|
  380. peertube\.qtg\.fr|
  381. video\.migennes\.net|
  382. tube\.p2p\.legal|
  383. troll\.tv|
  384. videos\.iut-orsay\.fr|
  385. peertube\.solidev\.net|
  386. videos\.cemea\.org|
  387. video\.passageenseine\.fr|
  388. videos\.festivalparminous\.org|
  389. peertube\.touhoppai\.moe|
  390. sikke\.fi|
  391. peer\.hostux\.social|
  392. share\.tube|
  393. peertube\.walkingmountains\.fr|
  394. videos\.benpro\.fr|
  395. peertube\.parleur\.net|
  396. peertube\.heraut\.eu|
  397. tube\.aquilenet\.fr|
  398. peertube\.gegeweb\.eu|
  399. framatube\.org|
  400. thinkerview\.video|
  401. tube\.conferences-gesticulees\.net|
  402. peertube\.datagueule\.tv|
  403. video\.lqdn\.fr|
  404. tube\.mochi\.academy|
  405. media\.zat\.im|
  406. video\.colibris-outilslibres\.org|
  407. tube\.svnet\.fr|
  408. peertube\.video|
  409. peertube3\.cpy\.re|
  410. peertube2\.cpy\.re|
  411. videos\.tcit\.fr|
  412. peertube\.cpy\.re
  413. )'''
  414. _UUID_RE = r'[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}'
  415. _API_BASE = 'https://%s/api/v1/videos/%s/%s'
  416. _VALID_URL = r'''(?x)
  417. (?:
  418. peertube:(?P<host>[^:]+):|
  419. https?://(?P<host_2>%s)/(?:videos/(?:watch|embed)|api/v\d/videos)/
  420. )
  421. (?P<id>%s)
  422. ''' % (_INSTANCES_RE, _UUID_RE)
  423. _TESTS = [{
  424. 'url': 'https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d',
  425. 'md5': '9bed8c0137913e17b86334e5885aacff',
  426. 'info_dict': {
  427. 'id': '9c9de5e8-0a1e-484a-b099-e80766180a6d',
  428. 'ext': 'mp4',
  429. 'title': 'What is PeerTube?',
  430. 'description': 'md5:3fefb8dde2b189186ce0719fda6f7b10',
  431. 'thumbnail': r're:https?://.*\.(?:jpg|png)',
  432. 'timestamp': 1538391166,
  433. 'upload_date': '20181001',
  434. 'uploader': 'Framasoft',
  435. 'uploader_id': '3',
  436. 'uploader_url': 'https://framatube.org/accounts/framasoft',
  437. 'channel': 'Les vidéos de Framasoft',
  438. 'channel_id': '2',
  439. 'channel_url': 'https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8',
  440. 'language': 'en',
  441. 'license': 'Attribution - Share Alike',
  442. 'duration': 113,
  443. 'view_count': int,
  444. 'like_count': int,
  445. 'dislike_count': int,
  446. 'tags': ['framasoft', 'peertube'],
  447. 'categories': ['Science & Technology'],
  448. }
  449. }, {
  450. 'url': 'https://peertube.tamanoir.foucry.net/videos/watch/0b04f13d-1e18-4f1d-814e-4979aa7c9c44',
  451. 'only_matching': True,
  452. }, {
  453. # nsfw
  454. 'url': 'https://tube.22decembre.eu/videos/watch/9bb88cd3-9959-46d9-9ab9-33d2bb704c39',
  455. 'only_matching': True,
  456. }, {
  457. 'url': 'https://tube.22decembre.eu/videos/embed/fed67262-6edb-4d1c-833b-daa9085c71d7',
  458. 'only_matching': True,
  459. }, {
  460. 'url': 'https://tube.openalgeria.org/api/v1/videos/c1875674-97d0-4c94-a058-3f7e64c962e8',
  461. 'only_matching': True,
  462. }, {
  463. 'url': 'peertube:video.blender.org:b37a5b9f-e6b5-415c-b700-04a5cd6ec205',
  464. 'only_matching': True,
  465. }]
  466. @staticmethod
  467. def _extract_peertube_url(webpage, source_url):
  468. mobj = re.match(
  469. r'https?://(?P<host>[^/]+)/videos/(?:watch|embed)/(?P<id>%s)'
  470. % PeerTubeIE._UUID_RE, source_url)
  471. if mobj and any(p in webpage for p in (
  472. '<title>PeerTube<',
  473. 'There will be other non JS-based clients to access PeerTube',
  474. '>We are sorry but it seems that PeerTube is not compatible with your web browser.<')):
  475. return 'peertube:%s:%s' % mobj.group('host', 'id')
  476. @staticmethod
  477. def _extract_urls(webpage, source_url):
  478. entries = re.findall(
  479. r'''(?x)<iframe[^>]+\bsrc=["\'](?P<url>(?:https?:)?//%s/videos/embed/%s)'''
  480. % (PeerTubeIE._INSTANCES_RE, PeerTubeIE._UUID_RE), webpage)
  481. if not entries:
  482. peertube_url = PeerTubeIE._extract_peertube_url(webpage, source_url)
  483. if peertube_url:
  484. entries = [peertube_url]
  485. return entries
  486. def _call_api(self, host, video_id, path, note=None, errnote=None, fatal=True):
  487. return self._download_json(
  488. self._API_BASE % (host, video_id, path), video_id,
  489. note=note, errnote=errnote, fatal=fatal)
  490. def _get_subtitles(self, host, video_id):
  491. captions = self._call_api(
  492. host, video_id, 'captions', note='Downloading captions JSON',
  493. fatal=False)
  494. if not isinstance(captions, dict):
  495. return
  496. data = captions.get('data')
  497. if not isinstance(data, list):
  498. return
  499. subtitles = {}
  500. for e in data:
  501. language_id = try_get(e, lambda x: x['language']['id'], compat_str)
  502. caption_url = urljoin('https://%s' % host, e.get('captionPath'))
  503. if not caption_url:
  504. continue
  505. subtitles.setdefault(language_id or 'en', []).append({
  506. 'url': caption_url,
  507. })
  508. return subtitles
  509. def _real_extract(self, url):
  510. mobj = re.match(self._VALID_URL, url)
  511. host = mobj.group('host') or mobj.group('host_2')
  512. video_id = mobj.group('id')
  513. video = self._call_api(
  514. host, video_id, '', note='Downloading video JSON')
  515. title = video['name']
  516. formats = []
  517. for file_ in video['files']:
  518. if not isinstance(file_, dict):
  519. continue
  520. file_url = url_or_none(file_.get('fileUrl'))
  521. if not file_url:
  522. continue
  523. file_size = int_or_none(file_.get('size'))
  524. format_id = try_get(
  525. file_, lambda x: x['resolution']['label'], compat_str)
  526. f = parse_resolution(format_id)
  527. f.update({
  528. 'url': file_url,
  529. 'format_id': format_id,
  530. 'filesize': file_size,
  531. })
  532. formats.append(f)
  533. self._sort_formats(formats)
  534. full_description = self._call_api(
  535. host, video_id, 'description', note='Downloading description JSON',
  536. fatal=False)
  537. description = None
  538. if isinstance(full_description, dict):
  539. description = str_or_none(full_description.get('description'))
  540. if not description:
  541. description = video.get('description')
  542. subtitles = self.extract_subtitles(host, video_id)
  543. def data(section, field, type_):
  544. return try_get(video, lambda x: x[section][field], type_)
  545. def account_data(field, type_):
  546. return data('account', field, type_)
  547. def channel_data(field, type_):
  548. return data('channel', field, type_)
  549. category = data('category', 'label', compat_str)
  550. categories = [category] if category else None
  551. nsfw = video.get('nsfw')
  552. if nsfw is bool:
  553. age_limit = 18 if nsfw else 0
  554. else:
  555. age_limit = None
  556. return {
  557. 'id': video_id,
  558. 'title': title,
  559. 'description': description,
  560. 'thumbnail': urljoin(url, video.get('thumbnailPath')),
  561. 'timestamp': unified_timestamp(video.get('publishedAt')),
  562. 'uploader': account_data('displayName', compat_str),
  563. 'uploader_id': str_or_none(account_data('id', int)),
  564. 'uploader_url': url_or_none(account_data('url', compat_str)),
  565. 'channel': channel_data('displayName', compat_str),
  566. 'channel_id': str_or_none(channel_data('id', int)),
  567. 'channel_url': url_or_none(channel_data('url', compat_str)),
  568. 'language': data('language', 'id', compat_str),
  569. 'license': data('licence', 'label', compat_str),
  570. 'duration': int_or_none(video.get('duration')),
  571. 'view_count': int_or_none(video.get('views')),
  572. 'like_count': int_or_none(video.get('likes')),
  573. 'dislike_count': int_or_none(video.get('dislikes')),
  574. 'age_limit': age_limit,
  575. 'tags': try_get(video, lambda x: x['tags'], list),
  576. 'categories': categories,
  577. 'formats': formats,
  578. 'subtitles': subtitles
  579. }