]> jfr.im git - yt-dlp.git/blame - yt_dlp/extractor/murrtube.py
[cleanup] Misc fixes
[yt-dlp.git] / yt_dlp / extractor / murrtube.py
CommitLineData
81228319 1# coding: utf-8
2from __future__ import unicode_literals
3
4import functools
5import json
6
7from .common import InfoExtractor
8from ..utils import (
9 ExtractorError,
10 OnDemandPagedList,
11 determine_ext,
12 int_or_none,
13 try_get,
14)
15
16
17class MurrtubeIE(InfoExtractor):
18 _VALID_URL = r'''(?x)
19 (?:
20 murrtube:|
21 https?://murrtube\.net/videos/(?P<slug>[a-z0-9\-]+)\-
22 )
23 (?P<id>[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12})
24 '''
25 _TEST = {
26 'url': 'https://murrtube.net/videos/inferno-x-skyler-148b6f2a-fdcc-4902-affe-9c0f41aaaca0',
27 'md5': '169f494812d9a90914b42978e73aa690',
28 'info_dict': {
29 'id': '148b6f2a-fdcc-4902-affe-9c0f41aaaca0',
30 'ext': 'mp4',
31 'title': 'Inferno X Skyler',
32 'description': 'Humping a very good slutty sheppy (roomate)',
33 'thumbnail': r're:^https?://.*\.jpg$',
34 'duration': 284,
35 'uploader': 'Inferno Wolf',
36 'age_limit': 18,
37 'comment_count': int,
38 'view_count': int,
39 'like_count': int,
40 'tags': ['hump', 'breed', 'Fursuit', 'murrsuit', 'bareback'],
41 }
42 }
43
44 def _download_gql(self, video_id, op, note=None, fatal=True):
45 result = self._download_json(
46 'https://murrtube.net/graphql',
47 video_id, note, data=json.dumps(op).encode(), fatal=fatal,
48 headers={'Content-Type': 'application/json'})
49 return result['data']
50
51 def _real_extract(self, url):
52 video_id = self._match_id(url)
53 data = self._download_gql(video_id, {
54 'operationName': 'Medium',
55 'variables': {
56 'id': video_id,
57 },
58 'query': '''\
59query Medium($id: ID!) {
60 medium(id: $id) {
61 title
62 description
63 key
64 duration
65 commentsCount
66 likesCount
67 viewsCount
68 thumbnailKey
69 tagList
70 user {
71 name
72 __typename
73 }
74 __typename
75 }
76}'''})
77 meta = data['medium']
78
79 storage_url = 'https://storage.murrtube.net/murrtube/'
80 format_url = storage_url + meta.get('key', '')
81 thumbnail = storage_url + meta.get('thumbnailKey', '')
82
83 if determine_ext(format_url) == 'm3u8':
84 formats = self._extract_m3u8_formats(
85 format_url, video_id, 'mp4', entry_protocol='m3u8_native', fatal=False)
86 else:
87 formats = [{'url': format_url}]
88
89 return {
90 'id': video_id,
91 'title': meta.get('title'),
92 'description': meta.get('description'),
93 'formats': formats,
94 'thumbnail': thumbnail,
95 'duration': int_or_none(meta.get('duration')),
96 'uploader': try_get(meta, lambda x: x['user']['name']),
97 'view_count': meta.get('viewsCount'),
98 'like_count': meta.get('likesCount'),
99 'comment_count': meta.get('commentsCount'),
100 'tags': meta.get('tagList'),
101 'age_limit': 18,
102 }
103
104
105class MurrtubeUserIE(MurrtubeIE):
106 IE_DESC = 'Murrtube user profile'
107 _VALID_URL = r'https?://murrtube\.net/(?P<id>[^/]+)$'
108 _TEST = {
109 'url': 'https://murrtube.net/stormy',
110 'info_dict': {
111 'id': 'stormy',
112 },
113 'playlist_mincount': 27,
114 }
115 _PAGE_SIZE = 10
116
117 def _fetch_page(self, username, user_id, page):
118 data = self._download_gql(username, {
119 'operationName': 'Media',
120 'variables': {
121 'limit': self._PAGE_SIZE,
122 'offset': page * self._PAGE_SIZE,
123 'sort': 'latest',
124 'userId': user_id,
125 },
126 'query': '''\
127query Media($q: String, $sort: String, $userId: ID, $offset: Int!, $limit: Int!) {
128 media(q: $q, sort: $sort, userId: $userId, offset: $offset, limit: $limit) {
129 id
130 __typename
131 }
132}'''},
133 'Downloading page {0}'.format(page + 1))
134 if data is None:
135 raise ExtractorError(f'Failed to retrieve video list for page {page + 1}')
136
137 media = data['media']
138
139 for entry in media:
140 yield self.url_result('murrtube:{0}'.format(entry['id']), MurrtubeIE.ie_key())
141
142 def _real_extract(self, url):
143 username = self._match_id(url)
144 data = self._download_gql(username, {
145 'operationName': 'User',
146 'variables': {
147 'id': username,
148 },
149 'query': '''\
150query User($id: ID!) {
151 user(id: $id) {
152 id
153 __typename
154 }
155}'''},
156 'Downloading user info')
157 if data is None:
158 raise ExtractorError('Failed to fetch user info')
159
160 user = data['user']
161
162 entries = OnDemandPagedList(functools.partial(
163 self._fetch_page, username, user.get('id')), self._PAGE_SIZE)
164
165 return self.playlist_result(entries, username)