youtube download
This commit is contained in:
@ -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
28
framework/downloader.py
Normal 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)
|
@ -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()
|
||||
|
@ -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)
|
||||
)
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user