documented the renderer section
This commit is contained in:
parent
db6d5d9e4c
commit
d819450e4b
File diff suppressed because it is too large
Load Diff
8040
documentation/html/youtube-music/search/general-result.json
Normal file
8040
documentation/html/youtube-music/search/general-result.json
Normal file
File diff suppressed because it is too large
Load Diff
59
documentation/html/youtube-music/search/search.md
Normal file
59
documentation/html/youtube-music/search/search.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Search
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
what is it | query | file
|
||||||
|
---|---|---
|
||||||
|
general search response | `psychonaut 4`, [general-result.json](general-result.json)
|
||||||
|
|
||||||
|
## A general search yields
|
||||||
|
|
||||||
|
- **Top Result**
|
||||||
|
- The top Artist
|
||||||
|
- The most popular songs of said artist
|
||||||
|
- **Songs** (3) excluding the top songs
|
||||||
|
- Videos (3)
|
||||||
|
- **Albums** (3)
|
||||||
|
- Community playlists (3)
|
||||||
|
- **Artists** (3) excluding the top artist
|
||||||
|
- if you search for a artist, it might return simmilar artists in style, not in name
|
||||||
|
|
||||||
|
### Different Renderers
|
||||||
|
|
||||||
|
#### `runs`
|
||||||
|
|
||||||
|
This should be pretty consistently all over the response be parsebal to a list of Music Elements.
|
||||||
|
|
||||||
|
`runs` usually is a list. If a element of the list has the key `navigationEndpoint`, it represents a music elements in a following manner:
|
||||||
|
|
||||||
|
- `text` the name
|
||||||
|
- `navigationEndpoint` -> `browseEndpoint`
|
||||||
|
- `browseId` the id of the artist/song/album...
|
||||||
|
- `browseEndpointContextSupportedConfigs` -> `browseEndpointContextMusicConfig` -> `pageType` the type of the header like element
|
||||||
|
|
||||||
|
#### musicCardShelfRenderer
|
||||||
|
|
||||||
|
Used by e.g. the `Top Results`.
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
|
||||||
|
- One Main-Element (a header like music object) | consists of these keys:
|
||||||
|
- `thumbnail` the image of the header
|
||||||
|
- `title` -> `runs`
|
||||||
|
- for details look [here](#runs).
|
||||||
|
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
You can get the contents (a list of [renderers](#musiccardshelfrenderer)) this way:
|
||||||
|
|
||||||
|
```python
|
||||||
|
data = r.json().get("contents", {}).get("tabbedSearchResultsRenderer", {}).get("tabs", [{}])[0].get("tabRenderer").get("content", {}).get("sectionListRenderer", {}).get("contents", [])
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the list contains following items, in following order:
|
||||||
|
|
||||||
|
1. _About these results_ (an infobutton)
|
||||||
|
2. The **Top result**
|
||||||
|
3. The **Songs** [_musicShelfRenderer_]
|
||||||
|
4. ...
|
1
src/music_kraken/pages/youtube_music/__init__.py
Normal file
1
src/music_kraken/pages/youtube_music/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .youtube_music import YoutubeMusic
|
@ -6,14 +6,16 @@ import json
|
|||||||
from dataclasses import dataclass
|
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, DEBUG
|
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 ...utils.functions import get_current_millis
|
||||||
|
if DEBUG:
|
||||||
|
from ...utils.debug_utils import dump_to_file
|
||||||
|
|
||||||
from ..objects import Source, DatabaseObject
|
from ...objects import Source, DatabaseObject
|
||||||
from .abstract import Page
|
from ..abstract import Page
|
||||||
from ..objects import (
|
from ...objects import (
|
||||||
Artist,
|
Artist,
|
||||||
Source,
|
Source,
|
||||||
SourcePages,
|
SourcePages,
|
||||||
@ -22,8 +24,8 @@ from ..objects import (
|
|||||||
Label,
|
Label,
|
||||||
Target
|
Target
|
||||||
)
|
)
|
||||||
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:
|
def get_youtube_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
||||||
@ -41,11 +43,15 @@ class YoutubeMusicConnection(Connection):
|
|||||||
|
|
||||||
--> average delay in between: 1.8875 min
|
--> average delay in between: 1.8875 min
|
||||||
"""
|
"""
|
||||||
def __init__(self, logger: logging.Logger):
|
def __init__(self, logger: logging.Logger, accept_language: str):
|
||||||
|
# https://stackoverflow.com/questions/30561260/python-change-accept-language-using-requests
|
||||||
super().__init__(
|
super().__init__(
|
||||||
host="https://music.youtube.com/",
|
host="https://music.youtube.com/",
|
||||||
logger=logger,
|
logger=logger,
|
||||||
hearthbeat_interval=113.25,
|
hearthbeat_interval=113.25,
|
||||||
|
header_values={
|
||||||
|
"Accept-Language": accept_language
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# cookie consent for youtube
|
# cookie consent for youtube
|
||||||
@ -88,7 +94,7 @@ class YoutubeMusic(Page):
|
|||||||
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, accept_language="en-US,en;q=0.5")
|
||||||
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="",
|
||||||
@ -214,6 +220,7 @@ class YoutubeMusic(Page):
|
|||||||
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]:
|
||||||
|
search_query = search_query.strip()
|
||||||
self.LOGGER.info(f"general search for {search_query}")
|
self.LOGGER.info(f"general search for {search_query}")
|
||||||
print(self.credentials)
|
print(self.credentials)
|
||||||
|
|
||||||
@ -249,7 +256,14 @@ class YoutubeMusic(Page):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
print(r)
|
self.LOGGER.debug(str(r))
|
||||||
|
# dump_to_file(f"{search_query}.json", r.content, is_json=True)
|
||||||
|
|
||||||
|
renderer_list = r.json().get("contents", {}).get("tabbedSearchResultsRenderer", {}).get("tabs", [{}])[0].get("tabRenderer").get("content", {}).get("sectionListRenderer", {}).get("contents", [])
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
for i, content in enumerate(renderer_list):
|
||||||
|
dump_to_file(f"{i}-renderer.json", json.dumps(content), is_json=True, exit_after_dump=False)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Song(title="Lore Ipsum")
|
Song(title="Lore Ipsum")
|
18
src/music_kraken/utils/debug_utils.py
Normal file
18
src/music_kraken/utils/debug_utils.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .path_manager import LOCATIONS
|
||||||
|
|
||||||
|
|
||||||
|
def dump_to_file(file_name: str, payload: str, is_json: bool = False, exit_after_dump: bool = True):
|
||||||
|
path = Path(LOCATIONS.TEMP_DIRECTORY, file_name)
|
||||||
|
print(f"Dumping payload to: \"{path}\"")
|
||||||
|
|
||||||
|
if is_json:
|
||||||
|
payload = json.dumps(json.loads(payload), indent=4)
|
||||||
|
|
||||||
|
with path.open("w") as f:
|
||||||
|
f.write(payload)
|
||||||
|
|
||||||
|
if exit_after_dump:
|
||||||
|
exit()
|
Loading…
Reference in New Issue
Block a user