added indexing on ar_album and artist placeholders
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.venv
|
||||||
@@ -32,6 +32,7 @@ from deezspot.libutils.utils import (
|
|||||||
set_path,
|
set_path,
|
||||||
trasform_sync_lyric,
|
trasform_sync_lyric,
|
||||||
create_zip,
|
create_zip,
|
||||||
|
sanitize_name,
|
||||||
)
|
)
|
||||||
from mutagen.flac import FLAC
|
from mutagen.flac import FLAC
|
||||||
from mutagen.mp3 import MP3
|
from mutagen.mp3 import MP3
|
||||||
@@ -1136,7 +1137,7 @@ class DW_PLAYLIST:
|
|||||||
infos_dw = API_GW.get_playlist_data(self.__ids)['data']
|
infos_dw = API_GW.get_playlist_data(self.__ids)['data']
|
||||||
|
|
||||||
# Extract playlist metadata - we'll use this in the track-level reporting
|
# Extract playlist metadata - we'll use this in the track-level reporting
|
||||||
playlist_name = self.__json_data['title']
|
playlist_name_sanitized = sanitize_name(self.__json_data['title'])
|
||||||
total_tracks = len(infos_dw)
|
total_tracks = len(infos_dw)
|
||||||
|
|
||||||
playlist = Playlist()
|
playlist = Playlist()
|
||||||
@@ -1146,7 +1147,7 @@ class DW_PLAYLIST:
|
|||||||
# m3u file will be placed in output_dir/playlists
|
# m3u file will be placed in output_dir/playlists
|
||||||
playlist_m3u_dir = os.path.join(self.__output_dir, "playlists")
|
playlist_m3u_dir = os.path.join(self.__output_dir, "playlists")
|
||||||
os.makedirs(playlist_m3u_dir, exist_ok=True)
|
os.makedirs(playlist_m3u_dir, exist_ok=True)
|
||||||
m3u_path = os.path.join(playlist_m3u_dir, f"{playlist_name}.m3u")
|
m3u_path = os.path.join(playlist_m3u_dir, f"{playlist_name_sanitized}.m3u")
|
||||||
if not os.path.exists(m3u_path):
|
if not os.path.exists(m3u_path):
|
||||||
with open(m3u_path, "w", encoding="utf-8") as m3u_file:
|
with open(m3u_path, "w", encoding="utf-8") as m3u_file:
|
||||||
m3u_file.write("#EXTM3U\n")
|
m3u_file.write("#EXTM3U\n")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
stock_quality = "MP3_320"
|
stock_quality = "MP3_320"
|
||||||
method_saves = ["0", "1", "2"]
|
|
||||||
|
|
||||||
qualities = {
|
qualities = {
|
||||||
"MP3_320": {
|
"MP3_320": {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
method_saves = ["0", "1", "2", "3"]
|
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
"dee", "spo"
|
"dee", "spo"
|
||||||
]
|
]
|
||||||
@@ -23,6 +21,5 @@ stock_recursive_quality = False
|
|||||||
stock_recursive_download = False
|
stock_recursive_download = False
|
||||||
stock_not_interface = False
|
stock_not_interface = False
|
||||||
stock_zip = False
|
stock_zip = False
|
||||||
method_save = 3
|
|
||||||
is_thread = False # WARNING FOR TRUE, LOOP ON DEFAULT
|
is_thread = False # WARNING FOR TRUE, LOOP ON DEFAULT
|
||||||
stock_real_time_dl = True
|
stock_real_time_dl = True
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from deezspot.libutils.others_settings import supported_link, header
|
|||||||
|
|
||||||
from os.path import (
|
from os.path import (
|
||||||
isdir, basename,
|
isdir, basename,
|
||||||
join, isfile
|
join, isfile, dirname
|
||||||
)
|
)
|
||||||
|
|
||||||
def link_is_valid(link):
|
def link_is_valid(link):
|
||||||
@@ -120,247 +120,184 @@ def what_kind(link):
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
def __get_tronc(string):
|
def __get_tronc(string):
|
||||||
l_encoded = len(string.encode())
|
return string[:len(string) - 1]
|
||||||
if l_encoded > 242:
|
|
||||||
n_tronc = len(string) - l_encoded - 242
|
|
||||||
else:
|
|
||||||
n_tronc = 242
|
|
||||||
return n_tronc
|
|
||||||
|
|
||||||
def apply_custom_format(format_str, metadata: dict, pad_tracks=True) -> str:
|
def apply_custom_format(format_str, metadata: dict, pad_tracks=True) -> str:
|
||||||
"""
|
|
||||||
Replaces placeholders in the format string with values from metadata.
|
|
||||||
Placeholders are denoted by %key%, for example: "%ar_album%/%album%".
|
|
||||||
The pad_tracks parameter controls whether track numbers are padded with leading zeros.
|
|
||||||
"""
|
|
||||||
def replacer(match):
|
def replacer(match):
|
||||||
key = match.group(1)
|
full_key = match.group(1) # e.g., "artist", "ar_album_1"
|
||||||
# Alias and special keys
|
|
||||||
if key == 'album_artist':
|
|
||||||
raw_value = metadata.get('ar_album', metadata.get('album_artist'))
|
|
||||||
elif key == 'year':
|
|
||||||
raw_value = metadata.get('release_date', metadata.get('year'))
|
|
||||||
elif key == 'date':
|
|
||||||
raw_value = metadata.get('release_date', metadata.get('date'))
|
|
||||||
elif key == 'discnum':
|
|
||||||
raw_value = metadata.get('disc_number', metadata.get('discnum'))
|
|
||||||
else:
|
|
||||||
# All other placeholders map directly
|
|
||||||
raw_value = metadata.get(key)
|
|
||||||
|
|
||||||
# Friendly names for missing metadata
|
# Check for specific indexed placeholders: artist_INDEX or ar_album_INDEX
|
||||||
key_mappings = {
|
# Allows %artist_1%, %ar_album_1%, etc.
|
||||||
'ar_album': 'album artist',
|
indexed_artist_match = re.fullmatch(r'(artist|ar_album)_(\d+)', full_key)
|
||||||
'album_artist': 'album artist',
|
|
||||||
'artist': 'artist',
|
|
||||||
'album': 'album',
|
|
||||||
'tracknum': 'track number',
|
|
||||||
'discnum': 'disc number',
|
|
||||||
'date': 'release date',
|
|
||||||
'year': 'year',
|
|
||||||
'genre': 'genre',
|
|
||||||
'isrc': 'ISRC',
|
|
||||||
'explicit': 'explicit flag',
|
|
||||||
'duration': 'duration',
|
|
||||||
'publisher': 'publisher',
|
|
||||||
'composer': 'composer',
|
|
||||||
'copyright': 'copyright',
|
|
||||||
'author': 'author',
|
|
||||||
'lyricist': 'lyricist',
|
|
||||||
'version': 'version',
|
|
||||||
'comment': 'comment',
|
|
||||||
'encodedby': 'encoded by',
|
|
||||||
'language': 'language',
|
|
||||||
'lyrics': 'lyrics',
|
|
||||||
'mood': 'mood',
|
|
||||||
'rating': 'rating',
|
|
||||||
'website': 'website',
|
|
||||||
'replaygain_album_gain': 'replaygain album gain',
|
|
||||||
'replaygain_album_peak': 'replaygain album peak',
|
|
||||||
'replaygain_track_gain': 'replaygain track gain',
|
|
||||||
'replaygain_track_peak': 'replaygain track peak',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Custom formatting for specific keys
|
if indexed_artist_match:
|
||||||
if key == 'tracknum' and pad_tracks and raw_value not in (None, ''):
|
base_key = indexed_artist_match.group(1) # "artist" or "ar_album"
|
||||||
try:
|
try:
|
||||||
return sanitize_name(f"{int(raw_value):02d}")
|
index = int(indexed_artist_match.group(2))
|
||||||
except (ValueError, TypeError):
|
except ValueError: # Should not happen with \d+ but good practice
|
||||||
pass
|
return ""
|
||||||
if key == 'discnum' and raw_value not in (None, ''):
|
|
||||||
try:
|
|
||||||
return sanitize_name(f"{int(raw_value):02d}")
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
pass
|
|
||||||
if key == 'year' and raw_value not in (None, ''):
|
|
||||||
m = re.match(r"^(\d{4})", str(raw_value))
|
|
||||||
if m:
|
|
||||||
return sanitize_name(m.group(1))
|
|
||||||
|
|
||||||
# Handle missing metadata with descriptive default
|
|
||||||
if raw_value in (None, ''):
|
|
||||||
friendly = key_mappings.get(key, key.replace('_', ' '))
|
|
||||||
return sanitize_name(f"Unknown {friendly}")
|
|
||||||
|
|
||||||
# Default handling
|
raw_value = metadata.get(base_key) # Get the value of "artist" or "ar_album"
|
||||||
return sanitize_name(str(raw_value))
|
items = []
|
||||||
return re.sub(r'%(\w+)%', replacer, format_str)
|
|
||||||
|
|
||||||
def __get_dir(song_metadata, output_dir, method_save, custom_dir_format=None, pad_tracks=True):
|
if isinstance(raw_value, str):
|
||||||
"""
|
# Split semicolon-separated strings and strip whitespace
|
||||||
Returns the final directory based either on a custom directory format string
|
items = [item.strip() for item in raw_value.split(';') if item.strip()]
|
||||||
or the legacy method_save logic.
|
elif isinstance(raw_value, list):
|
||||||
"""
|
# Convert all items to string, strip whitespace
|
||||||
if song_metadata is None:
|
items = [str(item).strip() for item in raw_value if str(item).strip()]
|
||||||
raise ValueError("song_metadata cannot be None")
|
# If raw_value is not string or list, items remains []
|
||||||
|
|
||||||
|
if items: # If we have a list of artists/ar_album
|
||||||
|
if 1 <= index <= len(items):
|
||||||
|
return items[index - 1]
|
||||||
|
elif items: # Index out of bounds, but list is not empty
|
||||||
|
return items[0] # Fallback to the first item
|
||||||
|
# If items is empty after processing, fall through
|
||||||
|
|
||||||
|
# Fallback if no items or base_key was not found or not list/string
|
||||||
|
return ""
|
||||||
|
|
||||||
if custom_dir_format is not None:
|
|
||||||
# Use the custom format string
|
|
||||||
dir_name = apply_custom_format(custom_dir_format, song_metadata, pad_tracks)
|
|
||||||
else:
|
else:
|
||||||
# Legacy logic based on method_save (for episodes or albums)
|
# Original non-indexed placeholder logic (for %album%, %title%, %artist%, %ar_album%, etc.)
|
||||||
if 'show' in song_metadata and 'name' in song_metadata:
|
value = metadata.get(full_key, '')
|
||||||
show = var_excape(song_metadata.get('show', ''))
|
if pad_tracks and full_key in ['tracknum', 'discnum']:
|
||||||
episode = var_excape(song_metadata.get('name', ''))
|
str_value = str(value)
|
||||||
if show and episode:
|
# Pad with leading zero if it's a single digit
|
||||||
dir_name = f"{show} - {episode}"
|
if str_value.isdigit() and len(str_value) == 1:
|
||||||
elif show:
|
return str_value.zfill(2)
|
||||||
dir_name = show
|
return str(value)
|
||||||
elif episode:
|
|
||||||
dir_name = episode
|
|
||||||
else:
|
|
||||||
dir_name = "Unknown Episode"
|
|
||||||
else:
|
|
||||||
album = var_excape(song_metadata.get('album', ''))
|
|
||||||
ar_album = var_excape(song_metadata.get('ar_album', ''))
|
|
||||||
if method_save == 0:
|
|
||||||
dir_name = f"{album} - {ar_album}"
|
|
||||||
elif method_save == 1:
|
|
||||||
dir_name = f"{ar_album}/{album}"
|
|
||||||
elif method_save == 2:
|
|
||||||
dir_name = f"{album} - {ar_album}"
|
|
||||||
elif method_save == 3:
|
|
||||||
dir_name = f"{album} - {ar_album}"
|
|
||||||
else:
|
|
||||||
dir_name = "Unknown"
|
|
||||||
|
|
||||||
# Prevent absolute paths and sanitize each directory segment
|
return re.sub(r'%([^%]+)%', replacer, format_str)
|
||||||
dir_name = dir_name.strip('/')
|
|
||||||
dir_name = '/'.join(sanitize_name(seg) for seg in dir_name.split('/') if seg)
|
def __get_dir(song_metadata, output_dir, custom_dir_format=None, pad_tracks=True):
|
||||||
final_dir = join(output_dir, dir_name)
|
# If custom_dir_format is explicitly empty or None, use output_dir directly
|
||||||
if not isdir(final_dir):
|
if not custom_dir_format:
|
||||||
makedirs(final_dir)
|
# Ensure output_dir itself exists, as __check_dir won't be called on a subpath
|
||||||
return final_dir
|
__check_dir(output_dir)
|
||||||
|
return output_dir
|
||||||
|
|
||||||
|
# Apply the custom format string.
|
||||||
|
# pad_tracks is passed along in case 'tracknum' or 'discnum' are used in dir format.
|
||||||
|
formatted_path_segment = apply_custom_format(custom_dir_format, song_metadata, pad_tracks)
|
||||||
|
|
||||||
|
# Sanitize each component of the formatted path segment
|
||||||
|
sanitized_path_segment = "/".join(
|
||||||
|
sanitize_name(part) for part in formatted_path_segment.split("/")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Join with the base output directory
|
||||||
|
path = join(output_dir, sanitized_path_segment)
|
||||||
|
|
||||||
|
# __check_dir will create the directory if it doesn't exist.
|
||||||
|
__check_dir(path)
|
||||||
|
return path
|
||||||
|
|
||||||
def set_path(
|
def set_path(
|
||||||
song_metadata, output_dir,
|
song_metadata, output_dir,
|
||||||
song_quality, file_format, method_save,
|
song_quality, file_format,
|
||||||
is_episode=False,
|
is_episode=False,
|
||||||
custom_dir_format=None,
|
custom_dir_format=None,
|
||||||
custom_track_format=None,
|
custom_track_format=None,
|
||||||
pad_tracks=True
|
pad_tracks=True
|
||||||
):
|
):
|
||||||
if song_metadata is None:
|
# Determine the directory for the song
|
||||||
raise ValueError("song_metadata cannot be None")
|
# method_save is removed, __get_dir now only relies on custom_dir_format
|
||||||
|
directory = __get_dir(
|
||||||
|
song_metadata,
|
||||||
|
output_dir,
|
||||||
|
custom_dir_format=custom_dir_format,
|
||||||
|
pad_tracks=pad_tracks
|
||||||
|
)
|
||||||
|
|
||||||
|
# Determine the filename for the song
|
||||||
|
# Default track format if no custom one is provided
|
||||||
|
if custom_track_format is None:
|
||||||
if is_episode:
|
if is_episode:
|
||||||
if custom_track_format is not None:
|
# Default for episodes: %title%
|
||||||
song_name = apply_custom_format(custom_track_format, song_metadata, pad_tracks)
|
# Episodes usually don't have artist/album context in the same way tracks do.
|
||||||
|
# Their 'album' is the show name, and 'artist' is the publisher.
|
||||||
|
custom_track_format = "%music%"
|
||||||
else:
|
else:
|
||||||
show = var_excape(song_metadata.get('show', ''))
|
# Default for tracks: %artist% - %title%
|
||||||
episode = var_excape(song_metadata.get('name', ''))
|
custom_track_format = "%artist% - %music%"
|
||||||
if show and episode:
|
|
||||||
song_name = f"{show} - {episode}"
|
|
||||||
elif show:
|
|
||||||
song_name = show
|
|
||||||
elif episode:
|
|
||||||
song_name = episode
|
|
||||||
else:
|
|
||||||
song_name = "Unknown Episode"
|
|
||||||
else:
|
|
||||||
if custom_track_format is not None:
|
|
||||||
song_name = apply_custom_format(custom_track_format, song_metadata, pad_tracks)
|
|
||||||
else:
|
|
||||||
album = var_excape(song_metadata.get('album', ''))
|
|
||||||
artist = var_excape(song_metadata.get('artist', ''))
|
|
||||||
music = var_excape(song_metadata.get('music', '')) # Track title
|
|
||||||
discnum = song_metadata.get('discnum', '')
|
|
||||||
tracknum = song_metadata.get('tracknum', '')
|
|
||||||
|
|
||||||
if method_save == 0:
|
# Apply the custom format string for the track filename.
|
||||||
song_name = f"{album} CD {discnum} TRACK {tracknum}"
|
# pad_tracks is passed along for track/disc numbers in filename.
|
||||||
elif method_save == 1:
|
track_filename_base = apply_custom_format(custom_track_format, song_metadata, pad_tracks)
|
||||||
try:
|
track_filename_base = sanitize_name(track_filename_base)
|
||||||
if pad_tracks:
|
|
||||||
tracknum = f"{int(tracknum):02d}" # Format as two digits with padding
|
|
||||||
else:
|
|
||||||
tracknum = f"{int(tracknum)}" # Format without padding
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
pass # Fallback to raw value
|
|
||||||
tracknum_clean = var_excape(str(tracknum))
|
|
||||||
tracktitle_clean = var_excape(music)
|
|
||||||
song_name = f"{tracknum_clean}. {tracktitle_clean}"
|
|
||||||
elif method_save == 2:
|
|
||||||
isrc = song_metadata.get('isrc', '')
|
|
||||||
song_name = f"{music} - {artist} [{isrc}]"
|
|
||||||
elif method_save == 3:
|
|
||||||
song_name = f"{discnum}|{tracknum} - {music} - {artist}"
|
|
||||||
|
|
||||||
# Sanitize song_name to remove invalid chars and prevent '/'
|
# Add quality and file format to the filename
|
||||||
song_name = sanitize_name(song_name)
|
if song_quality and file_format:
|
||||||
# Truncate to avoid filesystem limits
|
# Ensure file_format starts with a dot
|
||||||
max_length = 255 - len(output_dir) - len(file_format)
|
ext = file_format if file_format.startswith('.') else f".{file_format}"
|
||||||
song_name = song_name[:max_length]
|
filename = f"{track_filename_base} [{song_quality}]{ext}"
|
||||||
|
elif file_format: # Only file_format provided
|
||||||
|
ext = file_format if file_format.startswith('.') else f".{file_format}"
|
||||||
|
filename = f"{track_filename_base}{ext}"
|
||||||
|
else: # Neither provided (should not happen for standard audio)
|
||||||
|
filename = track_filename_base
|
||||||
|
|
||||||
# Build final path
|
return join(directory, filename)
|
||||||
song_dir = __get_dir(song_metadata, output_dir, method_save, custom_dir_format, pad_tracks)
|
|
||||||
__check_dir(song_dir)
|
|
||||||
n_tronc = __get_tronc(song_name)
|
|
||||||
song_path = f"{song_dir}/{song_name[:n_tronc]}{file_format}"
|
|
||||||
return song_path
|
|
||||||
|
|
||||||
def create_zip(
|
def create_zip(
|
||||||
tracks: list[Track],
|
tracks: list[Track],
|
||||||
output_dir=None,
|
output_dir=None,
|
||||||
song_metadata=None,
|
song_metadata=None, # Album/Playlist level metadata
|
||||||
song_quality=None,
|
song_quality=None, # Overall quality for the zip, if applicable
|
||||||
method_save=0,
|
zip_name=None, # Specific name for the zip file
|
||||||
zip_name=None
|
custom_dir_format=None # To determine zip name if not provided, and for paths inside zip
|
||||||
):
|
):
|
||||||
if not zip_name:
|
# Determine the zip file name and path
|
||||||
album = var_excape(song_metadata.get('album', ''))
|
if zip_name:
|
||||||
song_dir = __get_dir(song_metadata, output_dir, method_save)
|
# If zip_name is a full path, use it as is.
|
||||||
if method_save == 0:
|
# Otherwise, prepend output_dir.
|
||||||
zip_name = f"{album}"
|
if not basename(zip_name) == zip_name: # Checks if it's just a filename
|
||||||
elif method_save == 1:
|
actual_zip_path = zip_name
|
||||||
artist = var_excape(song_metadata.get('ar_album', ''))
|
|
||||||
zip_name = f"{album} - {artist}"
|
|
||||||
elif method_save == 2:
|
|
||||||
artist = var_excape(song_metadata.get('ar_album', ''))
|
|
||||||
upc = song_metadata.get('upc', '')
|
|
||||||
zip_name = f"{album} - {artist} {upc}"
|
|
||||||
elif method_save == 3:
|
|
||||||
artist = var_excape(song_metadata.get('ar_album', ''))
|
|
||||||
upc = song_metadata.get('upc', '')
|
|
||||||
zip_name = f"{album} - {artist} {upc}"
|
|
||||||
n_tronc = __get_tronc(zip_name)
|
|
||||||
zip_name = zip_name[:n_tronc]
|
|
||||||
zip_name += ".zip"
|
|
||||||
zip_path = f"{song_dir}/{zip_name}"
|
|
||||||
else:
|
else:
|
||||||
zip_path = zip_name
|
# Ensure output_dir exists for placing the zip file
|
||||||
|
if not output_dir:
|
||||||
|
# Fallback to a default if output_dir is not provided with a relative zip_name
|
||||||
|
output_dir = "."
|
||||||
|
__check_dir(output_dir)
|
||||||
|
actual_zip_path = join(output_dir, zip_name)
|
||||||
|
elif song_metadata and output_dir: # Construct default name if song_metadata and output_dir exist
|
||||||
|
# Use album/playlist name and quality for default zip name
|
||||||
|
# Sanitize the album/playlist name part of the zip file
|
||||||
|
name_part = sanitize_name(song_metadata.get('album', song_metadata.get('name', 'archive')))
|
||||||
|
quality_part = f" [{song_quality}]" if song_quality else ""
|
||||||
|
actual_zip_path = join(output_dir, f"{name_part}{quality_part}.zip")
|
||||||
|
else:
|
||||||
|
# Fallback zip name if not enough info
|
||||||
|
actual_zip_path = join(output_dir if output_dir else ".", "archive.zip")
|
||||||
|
|
||||||
z = ZipFile(zip_path, "w", ZIP_DEFLATED)
|
# Ensure the directory for the zip file exists
|
||||||
|
zip_dir = dirname(actual_zip_path)
|
||||||
|
__check_dir(zip_dir)
|
||||||
|
|
||||||
|
with ZipFile(actual_zip_path, 'w', ZIP_DEFLATED) as zf:
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
if not track.success:
|
if track.success and isfile(track.song_path):
|
||||||
continue
|
# Determine path inside the zip
|
||||||
c_song_path = track.song_path
|
# This uses the same logic as saving individual files,
|
||||||
song_path = basename(c_song_path)
|
# but relative to the zip root.
|
||||||
if not isfile(c_song_path):
|
# We pass an empty string as base_output_dir to set_path essentially,
|
||||||
continue
|
# so it generates a relative path structure.
|
||||||
z.write(c_song_path, song_path)
|
path_in_zip = set_path(
|
||||||
z.close()
|
track.tags, # Use individual track metadata for path inside zip
|
||||||
return zip_path
|
"", # Base output dir (empty for relative paths in zip)
|
||||||
|
track.quality,
|
||||||
|
track.file_format,
|
||||||
|
custom_dir_format=custom_dir_format, # Use album/playlist custom dir format
|
||||||
|
custom_track_format=track.tags.get('custom_track_format'), # Use track specific if available
|
||||||
|
pad_tracks=track.tags.get('pad_tracks', True)
|
||||||
|
)
|
||||||
|
# Remove leading slash if any, to ensure it's relative inside zip
|
||||||
|
path_in_zip = path_in_zip.lstrip('/').lstrip('\\')
|
||||||
|
|
||||||
|
zf.write(track.song_path, arcname=path_in_zip)
|
||||||
|
return actual_zip_path
|
||||||
|
|
||||||
def trasform_sync_lyric(lyric):
|
def trasform_sync_lyric(lyric):
|
||||||
sync_array = []
|
sync_array = []
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ class Preferences:
|
|||||||
self.recursive_quality = None
|
self.recursive_quality = None
|
||||||
self.recursive_download = None
|
self.recursive_download = None
|
||||||
self.not_interface = None
|
self.not_interface = None
|
||||||
self.method_save = None
|
|
||||||
self.make_zip = None
|
self.make_zip = None
|
||||||
self.real_time_dl = None ,
|
self.real_time_dl = None ,
|
||||||
self.custom_dir_format = None,
|
self.custom_dir_format = None,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from deezspot.libutils.utils import (
|
|||||||
set_path,
|
set_path,
|
||||||
create_zip,
|
create_zip,
|
||||||
request,
|
request,
|
||||||
|
sanitize_name,
|
||||||
)
|
)
|
||||||
from mutagen import File
|
from mutagen import File
|
||||||
from mutagen.easyid3 import EasyID3
|
from mutagen.easyid3 import EasyID3
|
||||||
@@ -1220,10 +1221,11 @@ class DW_PLAYLIST:
|
|||||||
# --- Prepare the m3u playlist file ---
|
# --- Prepare the m3u playlist file ---
|
||||||
playlist_m3u_dir = os.path.join(self.__output_dir, "playlists")
|
playlist_m3u_dir = os.path.join(self.__output_dir, "playlists")
|
||||||
os.makedirs(playlist_m3u_dir, exist_ok=True)
|
os.makedirs(playlist_m3u_dir, exist_ok=True)
|
||||||
m3u_path = os.path.join(playlist_m3u_dir, f"{playlist_name}.m3u")
|
playlist_name_sanitized = sanitize_name(playlist_name)
|
||||||
|
m3u_path = os.path.join(playlist_m3u_dir, f"{playlist_name_sanitized}.m3u")
|
||||||
if not os.path.exists(m3u_path):
|
if not os.path.exists(m3u_path):
|
||||||
with open(m3u_path, "w", encoding="utf-8") as m3u_file:
|
with open(m3u_path, "w", encoding="utf-8") as m3u_file:
|
||||||
m3u_file.write("#EXTM3U\n")
|
m3u_file.write("#EXTM3U\\n")
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
playlist = Playlist()
|
playlist = Playlist()
|
||||||
|
|||||||
Reference in New Issue
Block a user