implemented the automated fetching of the api key
This commit is contained in:
parent
d10b4fc1a1
commit
31bce2fcb1
@ -25,8 +25,7 @@ class Connection:
|
|||||||
accepted_response_codes: Set[int] = None,
|
accepted_response_codes: Set[int] = None,
|
||||||
semantic_not_found: bool = True,
|
semantic_not_found: bool = True,
|
||||||
sleep_after_404: float = 0.0,
|
sleep_after_404: float = 0.0,
|
||||||
hearthbeat: bool = False,
|
hearthbeat_interval = 0,
|
||||||
hearthbeat_interval = 0
|
|
||||||
):
|
):
|
||||||
if proxies is None:
|
if proxies is None:
|
||||||
proxies = PROXIES_LIST
|
proxies = PROXIES_LIST
|
||||||
@ -52,11 +51,16 @@ class Connection:
|
|||||||
self.session_is_occupied: bool = False
|
self.session_is_occupied: bool = False
|
||||||
|
|
||||||
self.hearthbeat_thread = None
|
self.hearthbeat_thread = None
|
||||||
if hearthbeat:
|
self.hearthbeat_interval = hearthbeat_interval
|
||||||
self.hearthbeat_thread = threading.Thread(target=self._hearthbeat_loop, args=(hearthbeat_interval, ), daemon=True)
|
|
||||||
self.hearthbeat_thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
|
def start_hearthbeat(self):
|
||||||
|
if self.hearthbeat_interval <= 0:
|
||||||
|
self.LOGGER.warning(f"Can't start a hearthbeat with {self.hearthbeat_interval}s in between.")
|
||||||
|
|
||||||
|
self.hearthbeat_thread = threading.Thread(target=self._hearthbeat_loop, args=(self.hearthbeat_interval, ), daemon=True)
|
||||||
|
self.hearthbeat_thread.start()
|
||||||
|
|
||||||
def hearthbeat_failed(self):
|
def hearthbeat_failed(self):
|
||||||
self.LOGGER.warning(f"I just died... (The hearthbeat failed)")
|
self.LOGGER.warning(f"I just died... (The hearthbeat failed)")
|
||||||
|
|
||||||
@ -145,9 +149,10 @@ class Connection:
|
|||||||
|
|
||||||
connection_failed = False
|
connection_failed = False
|
||||||
try:
|
try:
|
||||||
while self.session_is_occupied and not is_hearthbeat:
|
|
||||||
if self.session_is_occupied and not is_hearthbeat:
|
if self.session_is_occupied and not is_hearthbeat:
|
||||||
self.LOGGER.info(f"Waiting for the hearthbeat to finish.")
|
self.LOGGER.info(f"Waiting for the hearthbeat to finish.")
|
||||||
|
while self.session_is_occupied and not is_hearthbeat:
|
||||||
|
pass
|
||||||
|
|
||||||
r: requests.Response = request(request_url, timeout=timeout, headers=headers, **kwargs)
|
r: requests.Response = request(request_url, timeout=timeout, headers=headers, **kwargs)
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
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
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
import json
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import re
|
||||||
|
|
||||||
from music_kraken.utils.shared import PROXIES_LIST, YOUTUBE_MUSIC_LOGGER
|
from ..utils.exception.config import SettingValueError
|
||||||
|
from ..utils.shared import PROXIES_LIST, YOUTUBE_MUSIC_LOGGER
|
||||||
|
from ..utils.config import CONNECTION_SECTION, write_config
|
||||||
|
|
||||||
from ..objects import Source, DatabaseObject
|
from ..objects import Source, DatabaseObject
|
||||||
from .abstract import Page
|
from .abstract import Page
|
||||||
@ -30,21 +34,22 @@ class YoutubeMusicConnection(Connection):
|
|||||||
103.82
|
103.82
|
||||||
|
|
||||||
--> average delay in between: 1.8875 min
|
--> average delay in between: 1.8875 min
|
||||||
-->
|
|
||||||
|
|
||||||
===API=KEY===
|
|
||||||
AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30
|
|
||||||
can be found at `view-source:https://music.youtube.com/`
|
|
||||||
search for: "innertubeApiKey"
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, logger: logging.Logger):
|
def __init__(self, logger: logging.Logger):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
host="https://music.youtube.com/",
|
host="https://music.youtube.com/",
|
||||||
logger=logger,
|
logger=logger,
|
||||||
hearthbeat=True,
|
hearthbeat_interval=113.25,
|
||||||
hearthbeat_interval=113.25
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# cookie consent for youtube
|
||||||
|
# https://stackoverflow.com/a/66940841/16804841
|
||||||
|
self.session.cookies.set(
|
||||||
|
name='CONSENT', value='YES+cb.20210328-17-p0.en-GB+FX+{}'.format(random.randint(100, 999)),
|
||||||
|
path='/', domain='.youtube.com'
|
||||||
|
)
|
||||||
|
self.start_hearthbeat()
|
||||||
|
|
||||||
def hearthbeat(self):
|
def hearthbeat(self):
|
||||||
r = self.get("https://music.youtube.com/verify_session", is_hearthbeat=True)
|
r = self.get("https://music.youtube.com/verify_session", is_hearthbeat=True)
|
||||||
if r is None:
|
if r is None:
|
||||||
@ -59,6 +64,15 @@ class YoutubeMusicConnection(Connection):
|
|||||||
self.hearthbeat_failed()
|
self.hearthbeat_failed()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class YouTubeMusicCredentials:
|
||||||
|
api_key: str
|
||||||
|
|
||||||
|
# ctoken is probably short for continue-token
|
||||||
|
# It is probably not strictly necessary, but hey :))
|
||||||
|
ctoken: str
|
||||||
|
|
||||||
|
|
||||||
class YoutubeMusic(Page):
|
class YoutubeMusic(Page):
|
||||||
# CHANGE
|
# CHANGE
|
||||||
SOURCE_TYPE = SourcePages.PRESET
|
SOURCE_TYPE = SourcePages.PRESET
|
||||||
@ -66,9 +80,59 @@ class YoutubeMusic(Page):
|
|||||||
|
|
||||||
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(
|
||||||
|
api_key=CONNECTION_SECTION.YOUTUBE_MUSIC_API_KEY.object_from_value,
|
||||||
|
ctoken=""
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.credentials.api_key == "":
|
||||||
|
self._fetch_from_main_page()
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _fetch_from_main_page(self):
|
||||||
|
"""
|
||||||
|
===API=KEY===
|
||||||
|
AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30
|
||||||
|
can be found at `view-source:https://music.youtube.com/`
|
||||||
|
search for: "innertubeApiKey"
|
||||||
|
"""
|
||||||
|
r = self.connection.get("https://music.youtube.com/")
|
||||||
|
if r is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
content = r.text
|
||||||
|
|
||||||
|
# api key
|
||||||
|
api_key_pattern = (
|
||||||
|
r"(?<=\"innertubeApiKey\":\")(.*?)(?=\")",
|
||||||
|
r"(?<=\"INNERTUBE_API_KEY\":\")(.*?)(?=\")",
|
||||||
|
)
|
||||||
|
|
||||||
|
api_keys = []
|
||||||
|
for api_key_patter in api_key_pattern:
|
||||||
|
api_keys.extend(re.findall(api_key_patter, content))
|
||||||
|
|
||||||
|
found_a_good_api_key = False
|
||||||
|
for api_key in api_keys:
|
||||||
|
# save the first api key
|
||||||
|
api_key = api_keys[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
CONNECTION_SECTION.YOUTUBE_MUSIC_API_KEY.set_value(api_key)
|
||||||
|
except SettingValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
found_a_good_api_key = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if found_a_good_api_key:
|
||||||
|
write_config()
|
||||||
|
self.LOGGER.info(f"Found a valid API-KEY for {type(self).__name__}: \"{api_key}\"")
|
||||||
|
else:
|
||||||
|
self.LOGGER.error(f"Couldn't find an API-KEY 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)
|
||||||
|
|
||||||
|
@ -107,6 +107,12 @@ class ConnectionSection(Section):
|
|||||||
value="20"
|
value="20"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.YOUTUBE_MUSIC_API_KEY = StringAttribute(
|
||||||
|
name="youtube_music_api_key",
|
||||||
|
description="This is the API key used by YouTube-Music internally.\nDw. if it is empty, Rachel will fetch it automatically for you <333\n(she will also update outdated api keys/those that don't work)",
|
||||||
|
value="AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30"
|
||||||
|
)
|
||||||
|
|
||||||
self.ALL_YOUTUBE_URLS = UrlListAttribute(
|
self.ALL_YOUTUBE_URLS = UrlListAttribute(
|
||||||
name="youtube_url",
|
name="youtube_url",
|
||||||
description="This is used to detect, if an url is from youtube, or any alternativ frontend.\n"
|
description="This is used to detect, if an url is from youtube, or any alternativ frontend.\n"
|
||||||
@ -133,6 +139,7 @@ class ConnectionSection(Section):
|
|||||||
self.INVIDIOUS_INSTANCE,
|
self.INVIDIOUS_INSTANCE,
|
||||||
self.PIPED_INSTANCE,
|
self.PIPED_INSTANCE,
|
||||||
self.SLEEP_AFTER_YOUTUBE_403,
|
self.SLEEP_AFTER_YOUTUBE_403,
|
||||||
|
self.YOUTUBE_MUSIC_API_KEY,
|
||||||
self.ALL_YOUTUBE_URLS,
|
self.ALL_YOUTUBE_URLS,
|
||||||
self.SPONSOR_BLOCK
|
self.SPONSOR_BLOCK
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user