layed out api request
This commit is contained in:
parent
31bce2fcb1
commit
2db4ea72ef
@ -1,3 +1,4 @@
|
|||||||
|
// https://music.youtube.com/youtubei/v1/search?key=AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30&prettyPrint=false
|
||||||
// ctoken could be short for continue token
|
// ctoken could be short for continue token
|
||||||
{
|
{
|
||||||
"POST": {
|
"POST": {
|
||||||
@ -147,3 +148,64 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"context":
|
||||||
|
{
|
||||||
|
"client":
|
||||||
|
{
|
||||||
|
"hl":"en",
|
||||||
|
"gl":"DE",
|
||||||
|
"remoteHost":"87.123.241.85",
|
||||||
|
"deviceMake":"",
|
||||||
|
"deviceModel":"",
|
||||||
|
"visitorData":"CgtucS1ibEdPa045ZyiT4YWmBg%3D%3D",
|
||||||
|
"userAgent":"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0,gzip(gfe)",
|
||||||
|
"clientName":"WEB_REMIX",
|
||||||
|
"clientVersion":"1.20230724.00.00-canary_experiment",
|
||||||
|
"osName":"X11","osVersion":"","originalUrl":"https://music.youtube.com/?cbrd=1","platform":"DESKTOP","clientFormFactor":"UNKNOWN_FORM_FACTOR","configInfo":
|
||||||
|
{"appInstallData":"CJPhhaYGEJ3b_hIQsdWvBRC41a8FEL22rgUQ3ravBRD-ta8FEOe6rwUQw7f-EhDgtq8FEKnErwUQ6sOvBRCst68FEIXZ_hIQ5LP-EhDMrv4SELiLrgUQ65OuBRCMt68FEOPO_hIQwt7-EhDbz68FELTJrwUQ8qivBRD4ta8FEJbOrwUQzN-uBRCPw68FEP24_RIQhLavBRC1pq8FEKqy_hIQksuvBRCa0a8FEMy3_hIQjMuvBRCj1K8FEKXC_hIQ_eeoGBD51a8F","coldConfigData":"CJPhhaYGEOy6rQUQ65OuBRC9tq4FEKT-rgUQ6KivBRDyqK8FEIy3rwUQ4bqvBRDDxq8FEJ7HrwUQ88yvBRDbz68FEMDQrwUQmtGvBRDK068FENTTrwUQo9SvBRCx1a8FELjVrwUQ-dWvBRDZ168FEI7YrwUQ0NmvBRoyQU53R2I4V013TDV5bTJ1S0hPZndFWFZqcFB4b0l6MVRxcllyNFo2dDdKVGRTQjFFS3ciMkFOd0diOFdNd0w1eW0ydUtIT2Z3RVhWanBQeG9JejFUcXJZcjRaNnQ3SlRkU0IxRUt3KkhDQU1TTUEwVGdwYW9Bc2dXX2dXZkJJOFNuUXEwQW9FRWxnTVZINUtDMEF5elI4bVVCdDhhdmxLQ0F0NWluUy1KSjQtNUJBPT0%3D","coldHashData":"CJPhhaYGEhM0OTUzOTkxMTAyODE4MjI5NTY3GJPhhaYGMjJBTndHYjhXTXdMNXltMnVLSE9md0VYVmpwUHhvSXoxVHFyWXI0WjZ0N0pUZFNCMUVLdzoyQU53R2I4V013TDV5bTJ1S0hPZndFWFZqcFB4b0l6MVRxcllyNFo2dDdKVGRTQjFFS3dCSENBTVNNQTBUZ3Bhb0FzZ1dfZ1dmQkk4U25RcTBBb0VFbGdNVkg1S0MwQXl6UjhtVUJ0OGF2bEtDQXQ1aW5TLUpKNC01QkE9PQ%3D%3D","hotHashData":"CJPhhaYGEhQxMjc1MzUxNTg3MDYwNDg5NzEwMRiT4YWmBiiU5PwSKNuT_RIoxrL9EiiqtP0SKJ6R_hIomq3-EiiUzf4SKN3O_hIo487-EiiF2f4SKJfZ_hIondv-EijI3P4SKNjd_hIovt7-EjIyQU53R2I4V013TDV5bTJ1S0hPZndFWFZqcFB4b0l6MVRxcllyNFo2dDdKVGRTQjFFS3c6MkFOd0diOFdNd0w1eW0ydUtIT2Z3RVhWanBQeG9JejFUcXJZcjRaNnQ3SlRkU0IxRUt3QihDQU1TR1EwUDJJXzVGY29BcURrVkNvM2l6UXlMN2dIRmtBRGgwQUk9"},
|
||||||
|
"browserName":"Firefox",
|
||||||
|
"browserVersion":"115.0",
|
||||||
|
"acceptHeader":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||||
|
"deviceExperimentId":"ChxOekkyTURJd056ZzBPRFF3TWpVME5EVTRNUT09EJPhhaYGGJLhhaYG",
|
||||||
|
"screenWidthPoints":923,
|
||||||
|
"screenHeightPoints":964,
|
||||||
|
"screenPixelDensity":1,
|
||||||
|
"screenDensityFloat":1,
|
||||||
|
"utcOffsetMinutes":120,
|
||||||
|
"userInterfaceTheme":"USER_INTERFACE_THEME_DARK",
|
||||||
|
"timeZone":"Atlantic/Jan_Mayen",
|
||||||
|
"musicAppInfo":{"pwaInstallabilityStatus":"PWA_INSTALLABILITY_STATUS_UNKNOWN","webDisplayMode":"WEB_DISPLAY_MODE_BROWSER","storeDigitalGoodsApiSupportStatus":{"playStoreDigitalGoodsApiSupportStatus":"DIGITAL_GOODS_API_SUPPORT_STATUS_UNSUPPORTED"}}
|
||||||
|
},
|
||||||
|
"user":{"lockedSafetyMode":false},
|
||||||
|
"request":{"useSsl":true,"internalExperimentFlags":[],"consistencyTokenJars":[]
|
||||||
|
},
|
||||||
|
"adSignalsInfo":{
|
||||||
|
"params":[
|
||||||
|
{"key":"dt","value":"1690398867909"},
|
||||||
|
{"key":"flash","value":"0"},
|
||||||
|
{"key":"frm","value":"0"},
|
||||||
|
{"key":"u_tz","value":"120"},{"key":"u_his","value":"5"},{"key":"u_h","value":"1080"},{"key":"u_w","value":"1920"},{"key":"u_ah","value":"1049"},{"key":"u_aw","value":"1866"},{"key":"u_cd","value":"24"},{"key":"bc","value":"31"},{"key":"bih","value":"964"},{"key":"biw","value":"923"},{"key":"brdim","value":"1280,31,1280,31,1866,31,1866,1049,923,964"},{"key":"vis","value":"1"},{"key":"wgl","value":"true"},{"key":"ca_type","value":"image"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query":"psychonaut 4",
|
||||||
|
"suggestStats":{
|
||||||
|
"validationStatus":"VALID",
|
||||||
|
"parameterValidationStatus":"VALID_PARAMETERS",
|
||||||
|
"clientName":"youtube-music",
|
||||||
|
"searchMethod":"ENTER_KEY",
|
||||||
|
"inputMethod":"KEYBOARD",
|
||||||
|
"originalQuery":"psychonaut 4",
|
||||||
|
"availableSuggestions":[{"index":0,"suggestionType":0},{"index":1,"suggestionType":0},{"index":2,"suggestionType":0},{"index":3,"suggestionType":0},{"index":4,"suggestionType":0},{"index":5,"suggestionType":0},{"index":6,"suggestionType":0}],
|
||||||
|
"zeroPrefixEnabled":true,
|
||||||
|
"firstEditTimeMsec":1329258,
|
||||||
|
"lastEditTimeMsec":1330993
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -28,4 +28,8 @@ if __name__ == "__main__":
|
|||||||
"d: 5"
|
"d: 5"
|
||||||
]
|
]
|
||||||
|
|
||||||
music_kraken.cli.download(genre="test", command_list=download_youtube_playlist, process_metadata_anyway=True)
|
youtube_music_test = [
|
||||||
|
"s: psychonaut 4"
|
||||||
|
]
|
||||||
|
|
||||||
|
music_kraken.cli.download(genre="test", command_list=youtube_music_test, process_metadata_anyway=True)
|
||||||
|
@ -53,6 +53,10 @@ class Connection:
|
|||||||
self.hearthbeat_thread = None
|
self.hearthbeat_thread = None
|
||||||
self.hearthbeat_interval = hearthbeat_interval
|
self.hearthbeat_interval = hearthbeat_interval
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_agent(self) -> str:
|
||||||
|
return self.session.headers.get("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36")
|
||||||
|
|
||||||
|
|
||||||
def start_hearthbeat(self):
|
def start_hearthbeat(self):
|
||||||
if self.hearthbeat_interval <= 0:
|
if self.hearthbeat_interval <= 0:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from typing import Dict, List, Optional, Set, Type
|
from typing import Dict, List, Optional, Set, Type
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse, urlunparse, quote
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
@ -7,8 +7,9 @@ from dataclasses import dataclass
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ..utils.exception.config import SettingValueError
|
from ..utils.exception.config import SettingValueError
|
||||||
from ..utils.shared import PROXIES_LIST, YOUTUBE_MUSIC_LOGGER
|
from ..utils.shared import PROXIES_LIST, YOUTUBE_MUSIC_LOGGER, DEBUG
|
||||||
from ..utils.config import CONNECTION_SECTION, write_config
|
from ..utils.config import CONNECTION_SECTION, write_config
|
||||||
|
from ..utils.functions import get_current_millis
|
||||||
|
|
||||||
from ..objects import Source, DatabaseObject
|
from ..objects import Source, DatabaseObject
|
||||||
from .abstract import Page
|
from .abstract import Page
|
||||||
@ -24,6 +25,11 @@ from ..objects import (
|
|||||||
from ..connection import Connection
|
from ..connection import Connection
|
||||||
from ..utils.support_classes import DownloadResult
|
from ..utils.support_classes import DownloadResult
|
||||||
|
|
||||||
|
|
||||||
|
def get_youtube_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
||||||
|
return urlunparse(("https", "music.youtube.com", path, params, query, fragment))
|
||||||
|
|
||||||
|
|
||||||
class YoutubeMusicConnection(Connection):
|
class YoutubeMusicConnection(Connection):
|
||||||
"""
|
"""
|
||||||
===Hearthbeat=timings=for=YOUTUBEMUSIC===
|
===Hearthbeat=timings=for=YOUTUBEMUSIC===
|
||||||
@ -72,20 +78,76 @@ class YouTubeMusicCredentials:
|
|||||||
# It is probably not strictly necessary, but hey :))
|
# It is probably not strictly necessary, but hey :))
|
||||||
ctoken: str
|
ctoken: str
|
||||||
|
|
||||||
|
# the context in requests
|
||||||
|
context: dict
|
||||||
|
|
||||||
|
|
||||||
class YoutubeMusic(Page):
|
class YoutubeMusic(Page):
|
||||||
# CHANGE
|
# CHANGE
|
||||||
SOURCE_TYPE = SourcePages.PRESET
|
SOURCE_TYPE = SourcePages.YOUTUBE
|
||||||
LOGGER = YOUTUBE_MUSIC_LOGGER
|
LOGGER = YOUTUBE_MUSIC_LOGGER
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.connection: YoutubeMusicConnection = YoutubeMusicConnection(logger=self.LOGGER)
|
self.connection: YoutubeMusicConnection = YoutubeMusicConnection(logger=self.LOGGER)
|
||||||
self.credentials: YouTubeMusicCredentials = YouTubeMusicCredentials(
|
self.credentials: YouTubeMusicCredentials = YouTubeMusicCredentials(
|
||||||
api_key=CONNECTION_SECTION.YOUTUBE_MUSIC_API_KEY.object_from_value,
|
api_key=CONNECTION_SECTION.YOUTUBE_MUSIC_API_KEY.object_from_value,
|
||||||
ctoken=""
|
ctoken="",
|
||||||
|
context= {
|
||||||
|
"client": {
|
||||||
|
"hl": "en",
|
||||||
|
"gl": "DE",
|
||||||
|
"remoteHost": "87.123.241.77",
|
||||||
|
"deviceMake": "",
|
||||||
|
"deviceModel": "",
|
||||||
|
"visitorData": "CgtiTUxaTHpoXzk1Zyia59WlBg%3D%3D",
|
||||||
|
"userAgent": self.connection.user_agent,
|
||||||
|
"clientName": "WEB_REMIX",
|
||||||
|
"clientVersion": "1.20230710.01.00",
|
||||||
|
"osName": "X11",
|
||||||
|
"osVersion": "",
|
||||||
|
"originalUrl": "https://music.youtube.com/",
|
||||||
|
"platform": "DESKTOP",
|
||||||
|
"clientFormFactor": "UNKNOWN_FORM_FACTOR",
|
||||||
|
"configInfo": {
|
||||||
|
"appInstallData": "",
|
||||||
|
"coldConfigData": "",
|
||||||
|
"coldHashData": "",
|
||||||
|
"hotHashData": ""
|
||||||
|
},
|
||||||
|
"userInterfaceTheme": "USER_INTERFACE_THEME_DARK",
|
||||||
|
"timeZone": "Atlantic/Jan_Mayen",
|
||||||
|
"browserName": "Firefox",
|
||||||
|
"browserVersion": "115.0",
|
||||||
|
"acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||||
|
"deviceExperimentId": "ChxOekkxTmpnek16UTRNVFl4TkRrek1ETTVOdz09EJrn1aUGGJrn1aUG",
|
||||||
|
"screenWidthPoints": 584,
|
||||||
|
"screenHeightPoints": 939,
|
||||||
|
"screenPixelDensity": 1,
|
||||||
|
"screenDensityFloat": 1,
|
||||||
|
"utcOffsetMinutes": 120,
|
||||||
|
"musicAppInfo": {
|
||||||
|
"pwaInstallabilityStatus": "PWA_INSTALLABILITY_STATUS_UNKNOWN",
|
||||||
|
"webDisplayMode": "WEB_DISPLAY_MODE_BROWSER",
|
||||||
|
"storeDigitalGoodsApiSupportStatus": {
|
||||||
|
"playStoreDigitalGoodsApiSupportStatus": "DIGITAL_GOODS_API_SUPPORT_STATUS_UNSUPPORTED"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user": { "lockedSafetyMode": False },
|
||||||
|
"request": {
|
||||||
|
"useSsl": True,
|
||||||
|
"internalExperimentFlags": [],
|
||||||
|
"consistencyTokenJars": []
|
||||||
|
},
|
||||||
|
"adSignalsInfo": {
|
||||||
|
"params": []
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.credentials.api_key == "":
|
self.start_millis = get_current_millis()
|
||||||
|
|
||||||
|
if self.credentials.api_key == "" or DEBUG:
|
||||||
self._fetch_from_main_page()
|
self._fetch_from_main_page()
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -132,12 +194,64 @@ class YoutubeMusic(Page):
|
|||||||
else:
|
else:
|
||||||
self.LOGGER.error(f"Couldn't find an API-KEY for {type(self).__name__}. :((")
|
self.LOGGER.error(f"Couldn't find an API-KEY for {type(self).__name__}. :((")
|
||||||
|
|
||||||
|
# context
|
||||||
|
context_pattern = r"(?<=\"INNERTUBE_CONTEXT\":{)(.*?)(?=},\"INNERTUBE_CONTEXT_CLIENT_NAME\":)"
|
||||||
|
found_context = False
|
||||||
|
for context_string in re.findall(context_pattern, content):
|
||||||
|
try:
|
||||||
|
context = json.loads("{" + context_string + "}")
|
||||||
|
found_context
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.credentials.context = context
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found_context:
|
||||||
|
self.LOGGER.warning(f"Couldn't find a context for {type(self).__name__}.")
|
||||||
|
|
||||||
def get_source_type(self, source: Source) -> Optional[Type[DatabaseObject]]:
|
def get_source_type(self, source: Source) -> Optional[Type[DatabaseObject]]:
|
||||||
return super().get_source_type(source)
|
return super().get_source_type(source)
|
||||||
|
|
||||||
def general_search(self, search_query: str) -> List[DatabaseObject]:
|
def general_search(self, search_query: str) -> List[DatabaseObject]:
|
||||||
return []
|
self.LOGGER.info(f"general search for {search_query}")
|
||||||
|
print(self.credentials)
|
||||||
|
|
||||||
|
urlescaped_query: str = quote(search_query.strip().replace(" ", "+"))
|
||||||
|
|
||||||
|
LAST_EDITED_TIME = get_current_millis() - random.randint(0, 20)
|
||||||
|
_estimated_time = sum(len(search_query) * random.randint(50, 100) for _ in search_query.strip())
|
||||||
|
FIRST_EDITED_TIME = LAST_EDITED_TIME - _estimated_time if LAST_EDITED_TIME - self.start_millis > _estimated_time else random.randint(50, 100)
|
||||||
|
|
||||||
|
# construct the request
|
||||||
|
r = self.connection.post(
|
||||||
|
url=get_youtube_url(path="/youtubei/v1/search", query=f"key={self.credentials.api_key}&prettyPrint=false"),
|
||||||
|
json={
|
||||||
|
"context": {**self.credentials.context, "adSignalsInfo":{"params":[]}},
|
||||||
|
"query": search_query,
|
||||||
|
"suggestStats": {
|
||||||
|
"clientName": "youtube-music",
|
||||||
|
"firstEditTimeMsec": FIRST_EDITED_TIME,
|
||||||
|
"inputMethod": "KEYBOARD",
|
||||||
|
"lastEditTimeMsec": LAST_EDITED_TIME,
|
||||||
|
"originalQuery": search_query,
|
||||||
|
"parameterValidationStatus": "VALID_PARAMETERS",
|
||||||
|
"searchMethod": "ENTER_KEY",
|
||||||
|
"validationStatus": "VALID",
|
||||||
|
"zeroPrefixEnabled": True,
|
||||||
|
"availableSuggestions": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headers={
|
||||||
|
"Referer": get_youtube_url(path=f"/search", query=f"q={urlescaped_query}")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print(r)
|
||||||
|
|
||||||
|
return [
|
||||||
|
Song(title="Lore Ipsum")
|
||||||
|
]
|
||||||
|
|
||||||
def label_search(self, label: Label) -> List[Label]:
|
def label_search(self, label: Label) -> List[Label]:
|
||||||
return []
|
return []
|
||||||
|
@ -11,6 +11,7 @@ class SourceTypes(Enum):
|
|||||||
class SourcePages(Enum):
|
class SourcePages(Enum):
|
||||||
YOUTUBE = "youtube"
|
YOUTUBE = "youtube"
|
||||||
MUSIFY = "musify"
|
MUSIFY = "musify"
|
||||||
|
YOUTUBE_MUSIC = "youtube music"
|
||||||
GENIUS = "genius"
|
GENIUS = "genius"
|
||||||
MUSICBRAINZ = "musicbrainz"
|
MUSICBRAINZ = "musicbrainz"
|
||||||
ENCYCLOPAEDIA_METALLUM = "encyclopaedia metallum"
|
ENCYCLOPAEDIA_METALLUM = "encyclopaedia metallum"
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
def clear_console():
|
def clear_console():
|
||||||
os.system('cls' if os.name in ('nt', 'dos') else 'clear')
|
os.system('cls' if os.name in ('nt', 'dos') else 'clear')
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_millis() -> int:
|
||||||
|
dt = datetime.now()
|
||||||
|
return int(dt.microsecond / 1_000)
|
||||||
|
@ -126,3 +126,7 @@ FFMPEG_BINARY: Path = PATHS_SECTION.FFMPEG_BINARY.object_from_value
|
|||||||
|
|
||||||
HASNT_YET_STARTED: bool = MISC_SECTION.HASNT_YET_STARTED.object_from_value
|
HASNT_YET_STARTED: bool = MISC_SECTION.HASNT_YET_STARTED.object_from_value
|
||||||
SLEEP_AFTER_YOUTUBE_403: float = CONNECTION_SECTION.SLEEP_AFTER_YOUTUBE_403.object_from_value
|
SLEEP_AFTER_YOUTUBE_403: float = CONNECTION_SECTION.SLEEP_AFTER_YOUTUBE_403.object_from_value
|
||||||
|
|
||||||
|
DEBUG = True
|
||||||
|
if DEBUG:
|
||||||
|
print("DEBUG ACTIVE")
|
||||||
|
Loading…
Reference in New Issue
Block a user