mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 06:16:34 +03:00
Refine YouTube and Spotify music download process
This commit is contained in:
parent
a87385db78
commit
ffa1e9c69f
|
@ -33,7 +33,11 @@ def get_spotdl_client():
|
||||||
spot_settings = {
|
spot_settings = {
|
||||||
"simple_tui": True,
|
"simple_tui": True,
|
||||||
"log_level": "ERROR",
|
"log_level": "ERROR",
|
||||||
"lyrics_providers": ["genius", "musixmatch"],
|
"lyrics_providers": ["genius", "azlyrics", "musixmatch"],
|
||||||
|
"threads": 6,
|
||||||
|
"format": "mp3",
|
||||||
|
"ffmpeg": "ffmpeg",
|
||||||
|
"sponsor_block": True,
|
||||||
}
|
}
|
||||||
thread_local.spotdl_client = Spotdl(
|
thread_local.spotdl_client = Spotdl(
|
||||||
client_id=settings.MUSIC_SPOTIFY_ID,
|
client_id=settings.MUSIC_SPOTIFY_ID,
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pytube import Search, YouTube
|
from pytube import Search, YouTube
|
||||||
|
from spotdl.providers.audio import YouTubeMusic
|
||||||
|
|
||||||
from akarpov.music.models import Song
|
from akarpov.music.models import Song
|
||||||
from akarpov.music.services.db import load_track
|
from akarpov.music.services.db import load_track
|
||||||
|
@ -18,22 +19,28 @@
|
||||||
final_filename = None
|
final_filename = None
|
||||||
|
|
||||||
|
|
||||||
ydl_opts = {
|
ytmusic = YouTubeMusic()
|
||||||
"format": "m4a/bestaudio/best",
|
|
||||||
"postprocessors": [
|
|
||||||
{ # Extract audio using ffmpeg
|
|
||||||
"key": "FFmpegExtractAudio",
|
|
||||||
"preferredcodec": "m4a",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outtmpl": f"{settings.MEDIA_ROOT}/%(uploader)s_%(title)s.%(ext)s",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def download_file(url):
|
def download_file(url):
|
||||||
|
ydl_opts = {
|
||||||
|
"format": "bestaudio/best",
|
||||||
|
"outtmpl": f"{settings.MEDIA_ROOT}/%(uploader)s_%(title)s.%(ext)s",
|
||||||
|
"postprocessors": [
|
||||||
|
{"key": "SponsorBlock"}, # Skip sponsor segments
|
||||||
|
{
|
||||||
|
"key": "FFmpegExtractAudio",
|
||||||
|
"preferredcodec": "mp3",
|
||||||
|
"preferredquality": "192",
|
||||||
|
}, # Extract audio
|
||||||
|
{"key": "EmbedThumbnail"}, # Embed Thumbnail
|
||||||
|
{"key": "FFmpegMetadata"}, # Apply correct metadata
|
||||||
|
],
|
||||||
|
}
|
||||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||||
info = ydl.extract_info(url)
|
info = ydl.extract_info(url, download=True)
|
||||||
return info["requested_downloads"][0]["_filename"]
|
filename = ydl.prepare_filename(info)
|
||||||
|
return os.path.splitext(filename)[0] + ".mp3"
|
||||||
|
|
||||||
|
|
||||||
def parse_description(description: str) -> list:
|
def parse_description(description: str) -> list:
|
||||||
|
@ -67,7 +74,7 @@ def parse_description(description: str) -> list:
|
||||||
def download_from_youtube_link(link: str, user_id: int) -> Song:
|
def download_from_youtube_link(link: str, user_id: int) -> Song:
|
||||||
song = None
|
song = None
|
||||||
|
|
||||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
with yt_dlp.YoutubeDL({"ignoreerrors": True, "extract_flat": True}) as ydl:
|
||||||
info_dict = ydl.extract_info(link, download=False)
|
info_dict = ydl.extract_info(link, download=False)
|
||||||
title = info_dict.get("title", None)
|
title = info_dict.get("title", None)
|
||||||
description = info_dict.get("description", None)
|
description = info_dict.get("description", None)
|
||||||
|
@ -82,9 +89,12 @@ def download_from_youtube_link(link: str, user_id: int) -> Song:
|
||||||
+ slugify(orig_path.split("/")[-1].split(".")[0])
|
+ slugify(orig_path.split("/")[-1].split(".")[0])
|
||||||
+ ".mp3"
|
+ ".mp3"
|
||||||
)
|
)
|
||||||
AudioSegment.from_file(orig_path).export(path)
|
if orig_path.endswith(".mp3"):
|
||||||
if orig_path != path:
|
os.rename(orig_path, path)
|
||||||
os.remove(orig_path)
|
else:
|
||||||
|
AudioSegment.from_file(orig_path).export(path)
|
||||||
|
if orig_path != path:
|
||||||
|
os.remove(orig_path)
|
||||||
print(f"[processing] {title} converting to mp3: done")
|
print(f"[processing] {title} converting to mp3: done")
|
||||||
|
|
||||||
# split in chapters
|
# split in chapters
|
||||||
|
|
|
@ -3,14 +3,13 @@
|
||||||
import pylast
|
import pylast
|
||||||
import spotipy
|
import spotipy
|
||||||
import structlog
|
import structlog
|
||||||
import yt_dlp
|
import ytmusicapi
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from channels.layers import get_channel_layer
|
from channels.layers import get_channel_layer
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from pytube import Channel, Playlist
|
|
||||||
from spotipy import SpotifyClientCredentials
|
from spotipy import SpotifyClientCredentials
|
||||||
|
|
||||||
from akarpov.music.api.serializers import SongSerializer
|
from akarpov.music.api.serializers import SongSerializer
|
||||||
|
@ -40,19 +39,30 @@ def list_tracks(url, user_id):
|
||||||
yandex.load_playlist(url, user_id)
|
yandex.load_playlist(url, user_id)
|
||||||
if "youtube.com" in url:
|
if "youtube.com" in url:
|
||||||
if "channel" in url or "/c/" in url:
|
if "channel" in url or "/c/" in url:
|
||||||
channel = Channel(url)
|
ytmusic = ytmusicapi.YTMusic()
|
||||||
for video in channel.videos:
|
channel_id = url.split("/")[-1]
|
||||||
with yt_dlp.YoutubeDL({}) as ydl:
|
channel_songs = ytmusic.get_artist(channel_id)["songs"]["results"]
|
||||||
info = ydl.extract_info(video, download=False)
|
print(channel_songs)
|
||||||
if info.get("category") == "Music":
|
|
||||||
process_yb.apply_async(
|
for song in channel_songs:
|
||||||
kwargs={"url": video.watch_url, "user_id": user_id}
|
|
||||||
)
|
|
||||||
elif "playlist" in url or "&list=" in url:
|
|
||||||
playlist = Playlist(url)
|
|
||||||
for video in playlist.videos:
|
|
||||||
process_yb.apply_async(
|
process_yb.apply_async(
|
||||||
kwargs={"url": video.watch_url, "user_id": user_id}
|
kwargs={
|
||||||
|
"url": f"https://youtube.com/watch?v={song['videoId']}",
|
||||||
|
"user_id": user_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
elif "playlist" in url or "&list=" in url:
|
||||||
|
ytmusic = ytmusicapi.YTMusic()
|
||||||
|
playlist_id = url.split("=")[-1]
|
||||||
|
playlist_songs = ytmusic.get_playlist(playlist_id)["tracks"]["results"]
|
||||||
|
|
||||||
|
for song in playlist_songs:
|
||||||
|
process_yb.apply_async(
|
||||||
|
kwargs={
|
||||||
|
"url": f"https://music.youtube.com/watch?v={song['videoId']}",
|
||||||
|
"user_id": user_id,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
process_yb.apply_async(kwargs={"url": url, "user_id": user_id})
|
process_yb.apply_async(kwargs={"url": url, "user_id": user_id})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user