youtube download

This commit is contained in:
2023-05-06 03:16:26 +02:00
parent 71ff713417
commit 0749f742c3
27 changed files with 417 additions and 74 deletions

View File

@ -1,2 +1,4 @@
from .downloader import Downloader
from .redis import Redis
from .spotify import Spotify
from .youtube import Youtube

28
framework/downloader.py Normal file
View File

@ -0,0 +1,28 @@
from asyncio import AbstractEventLoop
from os import stat
from urllib.request import urlretrieve
from entity import File
class Downloader:
def __init__(self, loop: AbstractEventLoop) -> None:
self.loop = loop
def progress(self, progress, block_num: int, block_size: int, total_size: int):
self.loop.create_task(progress(block_num * block_size, total_size))
async def download(self, url: str, fileName: str, progress=None) -> File:
await self.loop.run_in_executor(
None,
lambda: urlretrieve(
url,
fileName,
lambda block_num, block_size, total_size: self.progress(
progress, block_num, block_size, total_size
)
if progress is not None
else None,
),
)
return File(name=fileName, size=stat(fileName).st_size)

View File

@ -1,13 +1,14 @@
from logging import Logger
from redis.asyncio.lock import Lock
import redis.asyncio as redis
import pickle
from logging import Logger
import redis.asyncio as redis
from redis.asyncio.lock import Lock
from config import RedisConfig
class Redis:
def __init__(self, logger: Logger, config: RedisConfig) -> None:
def __init__(self, logger: Logger, config: RedisConfig, rootKeyName: str) -> None:
self._client = redis.Redis(
host=config.host,
port=config.port,
@ -15,6 +16,7 @@ class Redis:
auto_close_connection_pool=False,
)
self._locks: dict[str, Lock] = {}
self.rootKeyName = rootKeyName
self.logger = logger
async def _get_lock(self, key) -> Lock:
@ -23,23 +25,23 @@ class Redis:
return self._locks[key]
async def acquire(self, key: str) -> None:
lock = await self._get_lock(f"djembe:queue:{key}")
lock = await self._get_lock(f"{self.rootKeyName}:queue:{key}")
await lock.acquire()
async def release(self, key: str) -> None:
lock = await self._get_lock(f"djembe:queue:{key}")
lock = await self._get_lock(f"{self.rootKeyName}:queue:{key}")
await lock.release()
async def get(self, key: str):
self.logger.info(f"get value {key} from redis")
value = await self._client.get(f"djembe:queue:{key}")
value = await self._client.get(f"{self.rootKeyName}:queue:{key}")
if value:
return pickle.loads(value)
return None
async def set(self, key: str, value) -> None:
self.logger.info(f"set value {key} to redis")
await self._client.set(f"djembe:queue:{key}", pickle.dumps(value))
await self._client.set(f"{self.rootKeyName}:queue:{key}", pickle.dumps(value))
async def close(self) -> None:
await self._client.close()

View File

@ -0,0 +1,25 @@
from asyncio import AbstractEventLoop
import spotipy
from spotipy import MemoryCacheHandler
from spotipy.oauth2 import SpotifyClientCredentials
from config import SpotifyConfig
class Spotify:
def __init__(self, loop: AbstractEventLoop, config: SpotifyConfig) -> None:
self.loop = loop
self.client = spotipy.Spotify(
auth_manager=SpotifyClientCredentials(
client_id=config.clientId,
client_secret=config.clientSecret,
cache_handler=MemoryCacheHandler(),
),
)
self.region = config.region
async def getTrack(self, url: str):
return await self.loop.run_in_executor(
None, lambda: self.client.track(url, self.region)
)

View File

@ -1,25 +1,79 @@
from yt_dlp import YoutubeDL
from youtubesearchpython.__future__ import VideosSearch
import re
from asyncio import AbstractEventLoop
from os import path, stat
from youtubesearchpython.__future__ import VideosSearch
from yt_dlp import YoutubeDL
from config import YoutubeConfig
from entity import File
class Youtube:
def __init__(self, loop: AbstractEventLoop, config: YoutubeConfig) -> None:
self.params = {}
self.client = YoutubeDL(self.params)
def __init__(
self, loop: AbstractEventLoop, config: YoutubeConfig, downloadDirectory: str
) -> None:
self.loop = loop
self.config = config
self.params = {
"format": "bestaudio/best",
"outtmpl": path.join(downloadDirectory, "%(id)s"),
"restrictfilenames": True,
"noplaylist": True,
"ignoreerrors": True,
"logtostderr": False,
"verbose": False,
"quiet": True,
"no_warnings": True,
"noprogress": True,
}
self.client = YoutubeDL(self.params)
self.language = config.language
self.region = config.region
self.get_id_regex = re.compile(
r"https:\/\/www\.youtube\.com\/watch\?v=(?P<id>[\w-]*)"
)
async def searchVideo(self, query: str):
videosSearch = VideosSearch(
query, limit=1, language=self.config.language, region=self.config.region
query, limit=1, language=self.language, region=self.region
)
return await videosSearch.next()
async def get_data(self, url: str) -> str:
data = await self.loop.run_in_executor(
async def fetchData(self, url: str):
info = await self.loop.run_in_executor(
None, lambda: self.client.extract_info(url, download=False)
)
print(data)
return self.client.sanitize_info(info)
def getId(self, url: str) -> str | None:
match = self.get_id_regex.search(url)
if match is None or "id" not in match.groupdict():
return None
return match.groupdict()["id"]
def downloadProgress(self, progress, status):
if status["status"] == "downloading":
self.loop.create_task(
progress(
int(status["downloaded_bytes"]),
int(
status["total_bytes"]
if "total_bytes" in status
else status["total_bytes_estimate"]
),
),
)
async def download(self, url: str, fileName: str, progress=None) -> None:
if progress is not None:
progress_hook = lambda status: self.downloadProgress(progress, status)
self.client.add_progress_hook(progress_hook)
await self.loop.run_in_executor(None, lambda: self.client.download(url))
if progress is not None:
self.client._progress_hooks.remove(progress_hook)
return File(name=fileName, size=stat(fileName).st_size)