mirror of
https://github.com/glomatico/gamdl.git
synced 2026-06-13 20:25:13 +03:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3096bbc79d | |||
| ed49d7bd5f | |||
| 0ea72d0b78 | |||
| ae490320ad | |||
| e40668e6ec | |||
| 62c695b5ff | |||
| 5d9c8c1f0b | |||
| 54d640230a | |||
| 3d272a6891 | |||
| e99ed0eb5a | |||
| 86b5029773 | |||
| 3df0a91d3f | |||
| d356596cf4 | |||
| cbd2df79b7 |
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "2.0"
|
||||
__version__ = "2.1.2"
|
||||
|
||||
+10
-8
@@ -491,14 +491,10 @@ def main(
|
||||
)
|
||||
else:
|
||||
stream_info = downloader_song.get_stream_info(track)
|
||||
if not stream_info.pssh:
|
||||
if not stream_info.stream_url:
|
||||
logger.warning(
|
||||
f"({queue_progress}) Song does not contain Widevine DRM, skipping"
|
||||
)
|
||||
continue
|
||||
elif not stream_info.stream_url:
|
||||
logger.warning(
|
||||
f"({queue_progress}) Song is not available with the selected codec, skipping"
|
||||
f"({queue_progress}) Song is not downloadable or is not"
|
||||
" available in the chosen codec, skipping"
|
||||
)
|
||||
continue
|
||||
logger.debug("Getting decryption key")
|
||||
@@ -527,7 +523,11 @@ def main(
|
||||
encrypted_path, decrypted_path, decryption_key
|
||||
)
|
||||
logger.debug(f"Remuxing to {final_path}")
|
||||
downloader_song.remux(decrypted_path, remuxed_path)
|
||||
downloader_song.remux(
|
||||
decrypted_path,
|
||||
remuxed_path,
|
||||
stream_info.codec,
|
||||
)
|
||||
logger.debug("Applying tags")
|
||||
downloader.apply_tags(remuxed_path, tags, cover_url)
|
||||
logger.debug(f"Moving to {final_path}")
|
||||
@@ -635,6 +635,8 @@ def main(
|
||||
decrypted_path_video,
|
||||
decrypted_path_audio,
|
||||
remuxed_path,
|
||||
stream_info_video.codec,
|
||||
stream_info_audio.codec,
|
||||
)
|
||||
logger.debug("Applying tags")
|
||||
downloader.apply_tags(remuxed_path, tags, cover_url)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
@@ -13,6 +14,8 @@ from .models import StreamInfo
|
||||
|
||||
|
||||
class DownloaderMusicVideo:
|
||||
MP4_FORMAT_CODECS = ["hvc1", "ec-3"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
downloader: Downloader,
|
||||
@@ -33,10 +36,10 @@ class DownloaderMusicVideo:
|
||||
).geturl()
|
||||
return m3u8.load(stream_url_master_new).data
|
||||
|
||||
def get_stream_url_video(
|
||||
def get_playlist_video(
|
||||
self,
|
||||
playlists: list[dict],
|
||||
):
|
||||
) -> dict:
|
||||
playlists_filtered = [
|
||||
playlist
|
||||
for playlist in playlists
|
||||
@@ -53,12 +56,12 @@ class DownloaderMusicVideo:
|
||||
)
|
||||
]
|
||||
playlists_filtered.sort(key=lambda x: x["stream_info"]["bandwidth"])
|
||||
return playlists_filtered[-1]["uri"]
|
||||
return playlists_filtered[-1]
|
||||
|
||||
def get_stream_url_video_from_user(
|
||||
def get_playlist_video_from_user(
|
||||
self,
|
||||
playlists: list[dict],
|
||||
):
|
||||
) -> dict:
|
||||
table = [
|
||||
[
|
||||
i,
|
||||
@@ -76,12 +79,12 @@ class DownloaderMusicVideo:
|
||||
)
|
||||
except click.exceptions.Abort:
|
||||
raise KeyboardInterrupt()
|
||||
return playlists[choice]["uri"]
|
||||
return playlists[choice]
|
||||
|
||||
def get_stream_url_audio(
|
||||
def get_playlist_audio(
|
||||
self,
|
||||
playlists: list[dict],
|
||||
) -> str:
|
||||
) -> dict:
|
||||
stream_url = next(
|
||||
(
|
||||
playlist
|
||||
@@ -89,13 +92,13 @@ class DownloaderMusicVideo:
|
||||
if playlist["group_id"] == "audio-stereo-256"
|
||||
),
|
||||
None,
|
||||
)["uri"]
|
||||
)
|
||||
return stream_url
|
||||
|
||||
def get_stream_url_audio_from_user(
|
||||
def get_playlist_audio_from_user(
|
||||
self,
|
||||
playlists: list[dict],
|
||||
):
|
||||
) -> dict:
|
||||
table = [
|
||||
[
|
||||
i,
|
||||
@@ -113,7 +116,7 @@ class DownloaderMusicVideo:
|
||||
)
|
||||
except click.exceptions.Abort:
|
||||
raise KeyboardInterrupt()
|
||||
return playlists[choice]["uri"]
|
||||
return playlists[choice]
|
||||
|
||||
def get_pssh(self, m3u8_data: dict):
|
||||
return next(
|
||||
@@ -128,13 +131,11 @@ class DownloaderMusicVideo:
|
||||
def get_stream_info_video(self, m3u8_master_data: dict) -> StreamInfo:
|
||||
stream_info = StreamInfo()
|
||||
if self.codec != MusicVideoCodec.ASK:
|
||||
stream_info.stream_url = self.get_stream_url_video(
|
||||
m3u8_master_data["playlists"]
|
||||
)
|
||||
playlist = self.get_playlist_video(m3u8_master_data["playlists"])
|
||||
else:
|
||||
stream_info.stream_url = self.get_stream_url_video_from_user(
|
||||
m3u8_master_data["playlists"]
|
||||
)
|
||||
playlist = self.get_playlist_video_from_user(m3u8_master_data["playlists"])
|
||||
stream_info.stream_url = playlist["uri"]
|
||||
stream_info.codec = playlist["stream_info"]["codecs"]
|
||||
m3u8_data = m3u8.load(stream_info.stream_url).data
|
||||
stream_info.pssh = self.get_pssh(m3u8_data)
|
||||
return stream_info
|
||||
@@ -142,13 +143,13 @@ class DownloaderMusicVideo:
|
||||
def get_stream_info_audio(self, m3u8_master_data: dict) -> StreamInfo:
|
||||
stream_info = StreamInfo()
|
||||
if self.codec != MusicVideoCodec.ASK:
|
||||
stream_info.stream_url = self.get_stream_url_audio(
|
||||
m3u8_master_data["media"]
|
||||
)
|
||||
playlist = self.get_playlist_audio(m3u8_master_data["media"])
|
||||
else:
|
||||
stream_info.stream_url = self.get_stream_url_audio_from_user(
|
||||
m3u8_master_data["media"]
|
||||
)
|
||||
playlist = self.get_playlist_audio_from_user(m3u8_master_data["media"])
|
||||
stream_info.stream_url = playlist["uri"]
|
||||
stream_info.codec = re.search(r"_([^_]+)\.m3u8", stream_info.stream_url).group(
|
||||
1
|
||||
)
|
||||
m3u8_data = m3u8.load(stream_info.stream_url).data
|
||||
stream_info.pssh = self.get_pssh(m3u8_data)
|
||||
return stream_info
|
||||
@@ -255,7 +256,12 @@ class DownloaderMusicVideo:
|
||||
decrypted_path_video: Path,
|
||||
decrypte_path_audio: Path,
|
||||
fixed_path: Path,
|
||||
codec_video: str,
|
||||
codec_audio: str,
|
||||
):
|
||||
use_mp4_flag = any(
|
||||
codec_video.startswith(codec) for codec in self.MP4_FORMAT_CODECS
|
||||
) or any(codec_audio.startswith(codec) for codec in self.MP4_FORMAT_CODECS)
|
||||
subprocess.run(
|
||||
[
|
||||
self.downloader.ffmpeg_path_full,
|
||||
@@ -269,7 +275,7 @@ class DownloaderMusicVideo:
|
||||
"-movflags",
|
||||
"+faststart",
|
||||
"-f",
|
||||
"mp4",
|
||||
"mp4" if use_mp4_flag else "ipod",
|
||||
"-c",
|
||||
"copy",
|
||||
"-c:s",
|
||||
@@ -284,6 +290,8 @@ class DownloaderMusicVideo:
|
||||
decrypted_path_video: Path,
|
||||
decrypted_path_audio: Path,
|
||||
remuxed_path: Path,
|
||||
codec_video: str,
|
||||
codec_audio: str,
|
||||
):
|
||||
if self.downloader.remux_mode == RemuxMode.MP4BOX:
|
||||
self.remux_mp4box(
|
||||
@@ -296,6 +304,8 @@ class DownloaderMusicVideo:
|
||||
decrypted_path_video,
|
||||
decrypted_path_audio,
|
||||
remuxed_path,
|
||||
codec_video,
|
||||
codec_audio,
|
||||
)
|
||||
|
||||
def get_cover_path(self, final_path: Path) -> Path:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import json
|
||||
@@ -19,6 +21,7 @@ from .models import Lyrics, StreamInfo
|
||||
|
||||
class DownloaderSong:
|
||||
DEFAULT_DECRYPTION_KEY = "32b8ade1769e26b1ffb8986352793fc6"
|
||||
MP4_FORMAT_CODECS = ["ec-3"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -40,7 +43,7 @@ class DownloaderSong:
|
||||
None,
|
||||
)
|
||||
if not drm_info_raw:
|
||||
raise Exception("DRM info not found")
|
||||
return None
|
||||
return json.loads(base64.b64decode(drm_info_raw["value"]).decode("utf-8"))
|
||||
|
||||
def get_asset_infos(self, m3u8_data: dict) -> dict:
|
||||
@@ -111,6 +114,8 @@ class DownloaderSong:
|
||||
m3u8_obj = m3u8.load(m3u8_url)
|
||||
m3u8_data = m3u8_obj.data
|
||||
drm_infos = self.get_drm_infos(m3u8_data)
|
||||
if not drm_infos:
|
||||
return stream_info
|
||||
asset_infos = self.get_asset_infos(m3u8_data)
|
||||
if self.codec == SongCodec.ASK:
|
||||
playlist = self.get_playlist_from_user(m3u8_data)
|
||||
@@ -123,6 +128,7 @@ class DownloaderSong:
|
||||
drm_ids = asset_infos[variant_id]["AUDIO-SESSION-KEY-IDS"]
|
||||
pssh = self.get_pssh(drm_infos, drm_ids)
|
||||
stream_info.pssh = pssh
|
||||
stream_info.codec = playlist["stream_info"]["codecs"]
|
||||
return stream_info
|
||||
|
||||
@staticmethod
|
||||
@@ -294,13 +300,13 @@ class DownloaderSong:
|
||||
check=True,
|
||||
)
|
||||
|
||||
def remux(self, decrypted_path: Path, remuxed_path: Path) -> None:
|
||||
def remux(self, decrypted_path: Path, remuxed_path: Path, codec: str):
|
||||
if self.downloader.remux_mode == RemuxMode.MP4BOX:
|
||||
self.remux_mp4box(decrypted_path, remuxed_path)
|
||||
elif self.downloader.remux_mode == RemuxMode.FFMPEG:
|
||||
self.remux_ffmpeg(decrypted_path, remuxed_path)
|
||||
self.remux_ffmpeg(decrypted_path, remuxed_path, codec)
|
||||
|
||||
def remux_mp4box(self, decrypted_path: Path, remuxed_path: Path) -> None:
|
||||
def remux_mp4box(self, decrypted_path: Path, remuxed_path: Path):
|
||||
subprocess.run(
|
||||
[
|
||||
self.downloader.mp4box_path_full,
|
||||
@@ -315,7 +321,16 @@ class DownloaderSong:
|
||||
check=True,
|
||||
)
|
||||
|
||||
def remux_ffmpeg(self, decrypted_path: Path, remuxed_path: Path) -> None:
|
||||
def remux_ffmpeg(
|
||||
self,
|
||||
decrypted_path: Path,
|
||||
remuxed_path: Path,
|
||||
codec: str,
|
||||
):
|
||||
use_mp4_format = any(
|
||||
codec.startswith(possible_codec)
|
||||
for possible_codec in self.MP4_FORMAT_CODECS
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
self.downloader.ffmpeg_path_full,
|
||||
@@ -326,6 +341,8 @@ class DownloaderSong:
|
||||
decrypted_path,
|
||||
"-c",
|
||||
"copy",
|
||||
"-f",
|
||||
"mp4" if use_mp4_format else "ipod",
|
||||
"-movflags",
|
||||
"+faststart",
|
||||
remuxed_path,
|
||||
|
||||
@@ -23,3 +23,4 @@ class Lyrics:
|
||||
class StreamInfo:
|
||||
stream_url: str = None
|
||||
pssh: str = None
|
||||
codec: str = None
|
||||
|
||||
Reference in New Issue
Block a user