implemented the ability to fetch playlists from piped
This commit is contained in:
parent
8278449ea3
commit
2a7452dc44
@ -1,5 +1,5 @@
|
|||||||
from .encyclopaedia_metallum import EncyclopaediaMetallum
|
from .encyclopaedia_metallum import EncyclopaediaMetallum
|
||||||
from .musify import Musify
|
from .musify import Musify
|
||||||
from .youtube.youtube import YouTube
|
from .youtube import YouTube
|
||||||
|
|
||||||
from .abstract import Page, INDEPENDENT_DB_OBJECTS
|
from .abstract import Page, INDEPENDENT_DB_OBJECTS
|
||||||
|
@ -5,9 +5,9 @@ from enum import Enum
|
|||||||
import sponsorblock
|
import sponsorblock
|
||||||
from sponsorblock.errors import HTTPException, NotFoundException
|
from sponsorblock.errors import HTTPException, NotFoundException
|
||||||
|
|
||||||
from ...objects import Source, DatabaseObject, Song, Target
|
from ..objects import Source, DatabaseObject, Song, Target
|
||||||
from ..abstract import Page
|
from .abstract import Page
|
||||||
from ...objects import (
|
from ..objects import (
|
||||||
Artist,
|
Artist,
|
||||||
Source,
|
Source,
|
||||||
SourcePages,
|
SourcePages,
|
||||||
@ -18,9 +18,9 @@ from ...objects import (
|
|||||||
FormattedText,
|
FormattedText,
|
||||||
ID3Timestamp
|
ID3Timestamp
|
||||||
)
|
)
|
||||||
from ...connection import Connection
|
from ..connection import Connection
|
||||||
from ...utils.support_classes import DownloadResult
|
from ..utils.support_classes import DownloadResult
|
||||||
from ...utils.shared import YOUTUBE_LOGGER, INVIDIOUS_INSTANCE, BITRATE, ENABLE_SPONSOR_BLOCK
|
from ..utils.shared import YOUTUBE_LOGGER, INVIDIOUS_INSTANCE, BITRATE, ENABLE_SPONSOR_BLOCK, PIPED_INSTANCE
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -34,6 +34,9 @@ from ...utils.shared import YOUTUBE_LOGGER, INVIDIOUS_INSTANCE, BITRATE, ENABLE_
|
|||||||
def get_invidious_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
def get_invidious_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
||||||
return urlunparse((INVIDIOUS_INSTANCE.scheme, INVIDIOUS_INSTANCE.netloc, path, params, query, fragment))
|
return urlunparse((INVIDIOUS_INSTANCE.scheme, INVIDIOUS_INSTANCE.netloc, path, params, query, fragment))
|
||||||
|
|
||||||
|
def get_piped_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
||||||
|
return urlunparse((PIPED_INSTANCE.scheme, PIPED_INSTANCE.netloc, path, params, query, fragment))
|
||||||
|
|
||||||
|
|
||||||
class YouTubeUrlType(Enum):
|
class YouTubeUrlType(Enum):
|
||||||
CHANNEL = "channel"
|
CHANNEL = "channel"
|
||||||
@ -138,6 +141,11 @@ class YouTube(Page):
|
|||||||
logger=self.LOGGER
|
logger=self.LOGGER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.piped_connection: Connection = Connection(
|
||||||
|
host=get_piped_url(),
|
||||||
|
logger=self.LOGGER
|
||||||
|
)
|
||||||
|
|
||||||
self.download_connection: Connection = Connection(
|
self.download_connection: Connection = Connection(
|
||||||
host="https://www.youtube.com/",
|
host="https://www.youtube.com/",
|
||||||
logger=self.LOGGER
|
logger=self.LOGGER
|
||||||
@ -294,17 +302,13 @@ class YouTube(Page):
|
|||||||
date=ID3Timestamp.fromtimestamp(round(sum(timestamps) / len(timestamps)))
|
date=ID3Timestamp.fromtimestamp(round(sum(timestamps) / len(timestamps)))
|
||||||
)
|
)
|
||||||
|
|
||||||
def fetch_artist(self, source: Source, stop_at_level: int = 1) -> Artist:
|
def fetch_invidious_album_list(self, yt_id: str):
|
||||||
parsed = YouTubeUrl(source.url)
|
|
||||||
if parsed.url_type != YouTubeUrlType.CHANNEL:
|
|
||||||
return Artist(source_list=[source])
|
|
||||||
|
|
||||||
artist_name = None
|
artist_name = None
|
||||||
album_list = []
|
album_list = []
|
||||||
|
|
||||||
# playlist
|
# playlist
|
||||||
# https://yt.artemislena.eu/api/v1/channels/playlists/UCV0Ntl3lVR7xDXKoCU6uUXA
|
# https://yt.artemislena.eu/api/v1/channels/playlists/UCV0Ntl3lVR7xDXKoCU6uUXA
|
||||||
r = self.connection.get(get_invidious_url(f"/api/v1/channels/playlists/{parsed.id}"))
|
r = self.connection.get(get_invidious_url(f"/api/v1/channels/playlists/{yt_id}"))
|
||||||
if r is None:
|
if r is None:
|
||||||
return Artist()
|
return Artist()
|
||||||
|
|
||||||
@ -328,6 +332,51 @@ class YouTube(Page):
|
|||||||
)]
|
)]
|
||||||
))
|
))
|
||||||
|
|
||||||
|
return album_list, artist_name
|
||||||
|
|
||||||
|
def fetch_piped_album_list(self, yt_id: str):
|
||||||
|
endpoint = get_piped_url(path=f"/channels/tabs", query='data={"originalUrl":"https://www.youtube.com/' + yt_id + '/playlists","url":"https://www.youtube.com/' + yt_id + 'playlists","id":"' + yt_id + '","contentFilters":["playlists"],"sortFilter":"","baseUrl":"https://www.youtube.com"}')
|
||||||
|
|
||||||
|
r = self.piped_connection.get(endpoint)
|
||||||
|
if r is None:
|
||||||
|
return [], None
|
||||||
|
|
||||||
|
content = r.json()["content"]
|
||||||
|
|
||||||
|
artist_name = None
|
||||||
|
album_list = []
|
||||||
|
|
||||||
|
for playlist in content:
|
||||||
|
if playlist["type"] != "playlist":
|
||||||
|
continue
|
||||||
|
|
||||||
|
artist_name = playlist["uploaderName"].replace(" - Topic", "")
|
||||||
|
|
||||||
|
album_list.append(Album(
|
||||||
|
title=playlist["name"],
|
||||||
|
source_list=[Source(
|
||||||
|
self.SOURCE_TYPE, get_invidious_url() + playlist["url"]
|
||||||
|
)],
|
||||||
|
artist_list=[Artist(
|
||||||
|
name=artist_name,
|
||||||
|
source_list=[
|
||||||
|
Source(self.SOURCE_TYPE, get_invidious_url(path=playlist["uploaderUrl"]))
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
))
|
||||||
|
|
||||||
|
return album_list, artist_name
|
||||||
|
|
||||||
|
def fetch_artist(self, source: Source, stop_at_level: int = 1) -> Artist:
|
||||||
|
parsed = YouTubeUrl(source.url)
|
||||||
|
if parsed.url_type != YouTubeUrlType.CHANNEL:
|
||||||
|
return Artist(source_list=[source])
|
||||||
|
|
||||||
|
album_list, artist_name = self.fetch_piped_album_list(parsed.id)
|
||||||
|
if len(album_list) <= 0:
|
||||||
|
self.LOGGER.warning(f"didn't found any playlists with piped, falling back to invidious. (it is unusual)")
|
||||||
|
album_list, artist_name = self.fetch_invidious_album_list(parsed.id)
|
||||||
|
|
||||||
return Artist(name=artist_name, main_album_list=album_list, source_list=[source])
|
return Artist(name=artist_name, main_album_list=album_list, source_list=[source])
|
||||||
|
|
||||||
def download_song_to_target(self, source: Source, target: Target, desc: str = None) -> DownloadResult:
|
def download_song_to_target(self, source: Source, target: Target, desc: str = None) -> DownloadResult:
|
@ -83,6 +83,9 @@ if TOR:
|
|||||||
'https': f'socks5h://127.0.0.1:{CONNECTION_SECTION.TOR_PORT.object_from_value}'
|
'https': f'socks5h://127.0.0.1:{CONNECTION_SECTION.TOR_PORT.object_from_value}'
|
||||||
}
|
}
|
||||||
INVIDIOUS_INSTANCE: ParseResult = CONNECTION_SECTION.INVIDIOUS_INSTANCE.object_from_value
|
INVIDIOUS_INSTANCE: ParseResult = CONNECTION_SECTION.INVIDIOUS_INSTANCE.object_from_value
|
||||||
|
PIPED_INSTANCE: ParseResult = CONNECTION_SECTION.PIPED_INSTANCE.object_from_value
|
||||||
|
|
||||||
|
ALL_YOUTUBE_URLS: List[ParseResult] = CONNECTION_SECTION.ALL_YOUTUBE_URLS.object_from_value
|
||||||
ENABLE_SPONSOR_BLOCK: bool = CONNECTION_SECTION.SPONSOR_BLOCK.object_from_value
|
ENABLE_SPONSOR_BLOCK: bool = CONNECTION_SECTION.SPONSOR_BLOCK.object_from_value
|
||||||
|
|
||||||
# size of the chunks that are streamed
|
# size of the chunks that are streamed
|
||||||
@ -102,5 +105,3 @@ THREADED = False
|
|||||||
|
|
||||||
ENABLE_RESULT_HISTORY: bool = MISC_SECTION.ENABLE_RESULT_HISTORY.object_from_value
|
ENABLE_RESULT_HISTORY: bool = MISC_SECTION.ENABLE_RESULT_HISTORY.object_from_value
|
||||||
HISTORY_LENGTH: int = MISC_SECTION.HISTORY_LENGTH.object_from_value
|
HISTORY_LENGTH: int = MISC_SECTION.HISTORY_LENGTH.object_from_value
|
||||||
|
|
||||||
ALL_YOUTUBE_URLS: List[ParseResult] = CONNECTION_SECTION.ALL_YOUTUBE_URLS.object_from_value
|
|
Loading…
Reference in New Issue
Block a user