1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# -*- coding: utf-8 -*-
# Copyright 2025 Mike Fährmann
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
"""Extractors for https://whyp.it/"""
from .common import Extractor, Message
from .. import text
BASE_PATTERN = r"(?:https?://)?(?:www\.)?whyp\.it"
class WhypExtractor(Extractor):
"""Base class for whyp extractors"""
category = "whyp"
root = "https://whyp.it"
root_api = "https://api.whyp.it"
directory_fmt = ("{category}", "{user[username]} ({user[id]})")
filename_fmt = "{id} {title}.{extension}"
archive_fmt = "{id}"
def _init(self):
self.headers_api = {
"Accept" : "application/json",
"Origin" : self.root,
"Referer": self.root + "/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
}
def items(self):
for track in self.tracks():
if url := track.get("lossless_url"):
track["original"] = True
else:
url = track["lossy_url"]
track["original"] = False
if "created_at" in track:
track["date"] = self.parse_datetime_iso(track["created_at"])
yield Message.Directory, "", track
yield Message.Url, url, text.nameext_from_url(url, track)
class WhypAudioExtractor(WhypExtractor):
subcategory = "audio"
pattern = BASE_PATTERN + r"/tracks/(\d+)"
example = "https://whyp.it/tracks/12345/SLUG"
def tracks(self):
url = f"{self.root_api}/api/tracks/{self.groups[0]}"
track = self.request_json(url, headers=self.headers_api)["track"]
return (track,)
class WhypUserExtractor(WhypExtractor):
subcategory = "user"
pattern = BASE_PATTERN + r"/users/(\d+)"
example = "https://whyp.it/users/123/NAME"
def tracks(self):
url = f"{self.root_api}/api/users/{self.groups[0]}/tracks"
params = {}
headers = self.headers_api
while True:
data = self.request_json(url, params=params, headers=headers)
yield from data["tracks"]
if not (cursor := data.get("next_cursor")):
break
params["cursor"] = cursor
class WhypCollectionExtractor(WhypExtractor):
subcategory = "collection"
pattern = BASE_PATTERN + r"/collections/(\d+)"
example = "https://whyp.it/collections/123/NAME"
def tracks(self):
cid = self.groups[0]
url = f"{self.root_api}/api/collections/{cid}"
headers = self.headers_api
self.kwdict["collection"] = collection = self.request_json(
url, headers=headers)["collection"]
url = f"{self.root_api}/api/collections/{cid}/tracks"
params = {"token": collection["token"]}
data = self.request_json(url, params=params, headers=headers)
return data["tracks"]
|