Skip to content

Commit

Permalink
Add album_artist to file path tags
Browse files Browse the repository at this point in the history
  • Loading branch information
justin025 committed Oct 24, 2024
1 parent 80de237 commit c6f7346
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 161 deletions.
65 changes: 18 additions & 47 deletions src/onthespot/api/soundcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import requests
from ..otsconfig import config
from ..runtimedata import get_logger, account_pool, pending
from ..utils import sanitize_data, make_call, translate
from ..utils import make_call, conv_list_format

SOUNDCLOUD_BASE = "https://api-v2.soundcloud.com"

Expand Down Expand Up @@ -206,10 +206,12 @@ def soundcloud_get_track_metadata(token, item_id):
# Many soundcloud songs are missing publisher metadata, parse if exists.

# Artists
try:
artists = [item.strip() for item in track_data['publisher_metadata']['artist'].split(',')]
except (KeyError, TypeError):
artists = [track_data['user']['username']]
artists = []
for item in track_data.get('publisher_metadata', {}).get('artist', '').split(','):
artists.append(item.strip())
artists = conv_list_format(artists)
if artists == '':
artists = track_data.get('user', {}).get('username', '')
# Track Number
try:
total_tracks = album_data['track_count']
Expand All @@ -233,64 +235,33 @@ def soundcloud_get_track_metadata(token, item_id):
if album_name.startswith("Users who like"):
album_name = track_data['title']

copyright = [item.strip() for item in track_data['publisher_metadata'].get('c_line', '').split(',')] if track_data.get('publisher_metadata', {}).get('c_line') else ""
publisher_metadata = track_data.get('publisher_metadata')
copyright = [item.strip() for item in publisher_metadata.get('c_line', '').split(',')] if publisher_metadata and publisher_metadata.get('c_line') else ""
copyright = conv_list_format(copyright)

info['image_url'] = track_data.get("artwork_url", "")
info['description'] = track_data.get("description", "")
info['genre'] = [track_data.get('genre', "")]
info['description'] = str(track_data.get("description", ""))
info['genre'] = conv_list_format([track_data.get('genre', [])])

label = track_data.get('label_name', "")
if label:
info['label'] = label
info['item_url'] = track_data.get('permalink_url', "")

release_date = track_data.get("release_date", track_data.get("last_modified", ""))
info['release_year'] = release_date.split("-")[0] if release_date else ""
release_date = track_data.get("release_date", "")
last_modified = track_data.get("last_modified", "")
info['release_year'] = release_date.split("-")[0] if release_date else last_modified.split("-")[0]

info['title'] = track_data.get("title", "")
info['track_number'] = track_number
info['total_tracks'] = total_tracks
info['file_url'] = track_file.get("url", "")
info['length'] = track_data.get("media", {}).get("transcodings", [{}])[0].get("duration", 0)
info['length'] = str(track_data.get("media", {}).get("transcodings", [{}])[0].get("duration", 0))
info['artists'] = artists
info['album_name'] = album_name
info['explicit'] = track_data['publisher_metadata'].get('explicit', False)
info['album_artists'] = track_data.get('user', {}).get('username', '')
info['explicit'] = publisher_metadata.get('explicit', False) if publisher_metadata else False
info['copyright'] = copyright
info['is_playable'] = track_data.get('streamable', '')

return info

def soundcloud_format_track_path(item_metadata, is_playlist_item, playlist_name, playlist_by):
if config.get("translate_file_path"):
_name = translate(item_metadata['title'])
_album = translate(item_metadata['album_name'])
else:
_name = item_metadata['title']
_album=item_metadata['album_name']

_artist = item_metadata['artists'][0]

if is_playlist_item is True and config.get("use_playlist_path"):
path = config.get("playlist_path_formatter")
else:
path = config.get("track_path_formatter")
item_path = path.format(
artist = sanitize_data(_artist),
album = sanitize_data(_album),
name = sanitize_data(_name),
rel_year = sanitize_data(item_metadata['release_year']),
disc_number = "",
track_number = item_metadata['track_number'],
genre = sanitize_data(item_metadata['genre'][0] if len(item_metadata['genre']) > 0 else ''),
explicit = sanitize_data(str(config.get('explicit')) if item_metadata['explicit'] else ''),
trackcount = item_metadata['total_tracks'],
disccount = "",
playlist_name = sanitize_data(playlist_name),
playlist_owner = sanitize_data(playlist_by),
)
if not config.get("force_raw"):
item_path = item_path + "." + config.get("media_format")
else:
item_path = item_path + ".mp3"
return item_path

111 changes: 21 additions & 90 deletions src/onthespot/api/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
from ..otsconfig import config, cache_dir
from ..runtimedata import get_logger, account_pool
from ..post_download import set_audio_tags
from ..utils import sanitize_data, make_call, translate, conv_list_format
from ..otsconfig import cache_dir, config
from ..runtimedata import get_logger
from ..utils import make_call, conv_list_format

logger = get_logger("spotify.api")

Expand Down Expand Up @@ -76,7 +74,6 @@ def spotify_new_session():
return True



def spotify_login_user(account):
# I'd prefer to use 'Session.Builder().stored(credentials).create but
# it seems to be broken, loading from credentials file instead
Expand All @@ -86,7 +83,7 @@ def spotify_login_user(account):
session_dir = os.path.join(cache_dir(), "onthespot", "sessions")
os.makedirs(session_dir, exist_ok=True)
session_json_path = os.path.join(session_dir, f"ots_login_{uuid}.json")

print(session_json_path)
try:
with open(session_json_path, 'w') as file:
json.dump(account['login'], file)
Expand Down Expand Up @@ -137,77 +134,6 @@ def spotify_login_user(account):
def spotify_get_token(parsing_index):
return account_pool[parsing_index]['login']['session']

def spotify_format_track_path(item_metadata, is_playlist_item, playlist_name, playlist_by):
if config.get("translate_file_path"):
_name = translate(item_metadata.get('title', ''))
_album = translate(item_metadata.get('album_name', ''))
else:
_name = item_metadata.get('title', '')
_album = item_metadata.get('album_name', '')

_artist = item_metadata['artists'][0]

if is_playlist_item and config.get("use_playlist_path"):
path = config.get("playlist_path_formatter")
else:
path = config.get("track_path_formatter")

item_path = path.format(
artist=sanitize_data(_artist),
album=sanitize_data(_album),
name=sanitize_data(_name),
rel_year=sanitize_data(item_metadata.get('release_year', '')),
disc_number=item_metadata.get('disc_number', 0),
track_number=item_metadata.get('track_number', 0),
genre=sanitize_data(item_metadata['genre'][0] if item_metadata.get('genre') else ''),
label=sanitize_data(item_metadata.get('label', '')),
explicit=sanitize_data(str(config.get('explicit')) if item_metadata.get('explicit') else ''),
trackcount=item_metadata.get('total_tracks', 0),
disccount=item_metadata.get('total_discs', 0),
playlist_name=sanitize_data(playlist_name),
playlist_owner=sanitize_data(playlist_by),
)

if not config.get("force_raw"):
item_path += "." + config.get("media_format")
else:
item_path += ".ogg"

return item_path

def spotify_format_episode_path(item_metadata, is_playlist_item, playlist_name, playlist_by):
if config.get("translate_file_path"):
_name = translate(item_metadata.get('title', ''))
_album = translate(item_metadata.get('album_name', ''))
else:
_name = item_metadata.get('title', '')
_album = item_metadata.get('album_name', '')

_artist = item_metadata['artists'][0]

if is_playlist_item and config.get("use_playlist_path"):
path = config.get("playlist_path_formatter")
else:
path = config.get("podcast_path_formatter")

item_path = path.format(
artist=sanitize_data(_artist),
album=sanitize_data(_album),
name=sanitize_data(_name),
rel_year=sanitize_data(item_metadata.get('release_year', '')),
explicit=sanitize_data(str(config.get('explicit')) if item_metadata.get('explicit') else ''),
total_episodes=item_metadata.get('total_tracks', 0),
language=item_metadata.get('language', 'unknown'),
playlist_name=sanitize_data(playlist_name),
playlist_owner=sanitize_data(playlist_by),
)

if not config.get("force_raw"):
item_path = item_path + "." + config.get("media_format")
else:
item_path = item_path + ".ogg"

return item_path

def spotify_get_artist_albums(session, artist_id):
logger.info(f"Get albums for artist by id '{artist_id}'")
Expand Down Expand Up @@ -274,7 +200,7 @@ def spotify_get_lyrics(session, item_id, item_type, metadata, filepath):
lyrics.append(f'[by:{resp["lyrics"]["provider"]}]')

if config.get("embed_length"):
l_ms = metadata['length']
l_ms = int(metadata['length'])
if round((l_ms/1000)/60) < 10:
digit="0"
else:
Expand Down Expand Up @@ -378,13 +304,14 @@ def spotify_get_album_tracks(session, album_id):
break
return songs


def spotify_get_search_results(session, search_term, content_types):
logger.info(
f"Get search result for term '{search_term}'"
)
if search_term.strip() == "":
logger.warning(f"Returning empty data as query is empty !")
return results
return ''
if content_types is None:
content_types = ["track", "album", "playlist", "artist", "show", "episode", "audiobook"]
token = session.tokens().get("user-read-email")
Expand All @@ -401,8 +328,7 @@ def spotify_get_search_results(session, search_term, content_types):
print(",".join(c_type for c_type in content_types))
print(data)
search_results = []

# Iterate over the keys in the response

for key in data.keys():
for item in data[key]["items"]:
item_type = item['type']
Expand Down Expand Up @@ -470,13 +396,15 @@ def spotify_get_track_metadata(session, item_id):
artists = []
for data in track_data.get('tracks', [{}])[0].get('artists', []):
artists.append(data.get('name', ''))
artists = conv_list_format(artists)

credits = {}
for credit_block in credits_data.get('roleCredits', []):
role_title = credit_block.get('roleTitle', '').lower()
credits[role_title] = [
artist.get('name', '') for artist in credit_block.get('artists', [])
]


info['artists'] = artists
info['album_name'] = track_data.get('tracks', [{}])[0].get('album', {}).get("name", '')
Expand All @@ -497,15 +425,15 @@ def spotify_get_track_metadata(session, item_id):

info['total_discs'] = sorted([trk.get('disc_number', 0) for trk in album_data.get('tracks', {}).get('items', [])])[-1] if 'tracks' in album_data else 1

info['genre'] = artist_data.get('genres', [])
info['performers'] = [item for item in credits.get('performers', []) if isinstance(item, str)]
info['producers'] = [item for item in credits.get('producers', []) if isinstance(item, str)]
info['writers'] = [item for item in credits.get('writers', []) if isinstance(item, str)]
info['genre'] = conv_list_format(artist_data.get('genres', []))
info['performers'] = conv_list_format([item for item in credits.get('performers', []) if isinstance(item, str)])
info['producers'] = conv_list_format([item for item in credits.get('producers', []) if isinstance(item, str)])
info['writers'] = conv_list_format([item for item in credits.get('writers', []) if isinstance(item, str)])
info['label'] = album_data.get('label', '')
info['copyright'] = [holder.get('text', '') for holder in album_data.get('copyrights', [])]
info['explicit'] = track_data.get('tracks', [{}])[0].get('explicit', False)
info['isrc'] = track_data.get('tracks', [{}])[0].get('external_ids', {}).get('isrc', '')
info['length'] = track_data.get('tracks', [{}])[0].get('duration_ms', '')
info['length'] = str(track_data.get('tracks', [{}])[0].get('duration_ms', ''))
info['item_url'] = track_data.get('tracks', [{}])[0].get('external_urls', {}).get('spotify', '')
info['popularity'] = track_data.get('tracks', [{}])[0].get('popularity', '') # unused
info['scraped_song_id'] = track_data.get('tracks', [{}])[0].get('id', '')
Expand All @@ -526,8 +454,8 @@ def spotify_get_track_metadata(session, item_id):
11: "B"
}

info['bpm'] = track_audio_data.get('tempo', '')
info['key'] = key_mapping.get(track_audio_data.get('key', ''), '')
info['bpm'] = str(track_audio_data.get('tempo', ''))
info['key'] = str(key_mapping.get(track_audio_data.get('key', ''), ''))
info['time_signature'] = track_audio_data.get('time_signature', '')
info['acousticness'] = track_audio_data.get('acousticness', '')
info['danceability'] = track_audio_data.get('danceability', '')
Expand All @@ -539,6 +467,7 @@ def spotify_get_track_metadata(session, item_id):
info['valence'] = track_audio_data.get('valence', '')
return info


def spotify_get_episode_metadata(token, episode_id_str):
logger.info(f"Get episode info for episode by id '{episode_id_str}'")

Expand All @@ -555,16 +484,18 @@ def spotify_get_episode_metadata(token, episode_id_str):
info['image_url'] = episode_data.get('images', [{}])[0].get('url', "")
info['release_year'] = episode_data.get('release_date', "")
info['total_tracks'] = episode_data.get('show', {}).get('total_episodes', 0)
info['artists'] = [episode_data.get('show', {}).get('publisher', "")]
info['artists'] = conv_list_format([episode_data.get('show', {}).get('publisher', "")])
info['album_artists'] = conv_list_format([episode_data.get('show', {}).get('publisher', "")])
info['language'] = conv_list_format(languages)
info['description'] = episode_data.get('description', "") if episode_data.get('description', "") != "" else ""
info['description'] = str(episode_data.get('description', "") if episode_data.get('description', "") != "" else "")
info['copyright'] = episode_data.get('show', {}).get('copyrights', [])
info['length'] = episode_data.get('duration_ms', 0)
info['length'] = str(episode_data.get('duration_ms', ''))
info['explicit'] = episode_data.get('explicit', '')
info['is_playable'] = episode_data.get('is_playable', '')

return info


def spotify_get_show_episodes(session, show_id_str):
logger.info(f"Get episodes for show by id '{show_id_str}'")
token = session.tokens().get("user-read-email")
Expand Down
10 changes: 5 additions & 5 deletions src/onthespot/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
from .runtimedata import get_logger, download_queue
from .otsconfig import config
from .post_download import convert_audio_format, set_audio_tags, set_music_thumbnail
from .api.spotify import spotify_get_token, spotify_get_track_metadata, spotify_get_episode_metadata, spotify_format_track_path, spotify_format_episode_path, spotify_get_lyrics
from .api.soundcloud import soundcloud_get_token, soundcloud_get_track_metadata, soundcloud_format_track_path
from .api.spotify import spotify_get_token, spotify_get_track_metadata, spotify_get_episode_metadata, spotify_get_lyrics
from .api.soundcloud import soundcloud_get_token, soundcloud_get_track_metadata
from .accounts import get_account_token
from .utils import sanitize_data, conv_list_format
from .utils import sanitize_data, conv_list_format, format_track_path

logger = get_logger("spotify.downloader")

Expand Down Expand Up @@ -58,7 +58,7 @@ def run(self):
try:
item_metadata = globals()[f"{item_service}_get_{item_type}_metadata"](token, item_id)

item_path = globals()[f"{item_service}_format_{item_type}_path"](item_metadata, item['is_playlist_item'], item['playlist_name'], item['playlist_by'])
item_path = format_track_path(item_metadata, item_service, item_type, item['is_playlist_item'], item['playlist_name'], item['playlist_by'])

except (Exception, KeyError):
logger.error(
Expand Down Expand Up @@ -172,7 +172,7 @@ def run(self):
globals()[f"{item_service}_get_lyrics"](token, item_id, item_type, item_metadata, file_path)

# M3U
if config.get('create_m3u_playlists') and item['is_playlist_item']:
if config.get('create_m3u_playlists') and item.get('is_playlist_item', False):
if self.gui:
self.progress.emit(item, self.tr("Adding To M3U"), 99)

Expand Down
13 changes: 8 additions & 5 deletions src/onthespot/gui/mainui.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from .thumb_listitem import LabelWithThumb
from ..api.spotify import spotify_get_token, spotify_get_track_metadata, spotify_get_episode_metadata, spotify_new_session
from ..api.soundcloud import soundcloud_get_token, soundcloud_get_track_metadata
from ..post_download import conv_list_format
from ..accounts import get_account_token, FillAccountPool
from ..search import get_search_results
from ..downloader import DownloadWorker
Expand Down Expand Up @@ -181,7 +180,7 @@ def add_item_to_download_list(self, item, item_metadata):
# Add To List
self.tbl_dl_progress.setItem(rows, 0, QTableWidgetItem(str(item['item_id'])))
self.tbl_dl_progress.setCellWidget(rows, 1, item_label)
self.tbl_dl_progress.setItem(rows, 2, QTableWidgetItem(conv_list_format(item_metadata['artists'])))
self.tbl_dl_progress.setItem(rows, 2, QTableWidgetItem(item_metadata['artists']))
self.tbl_dl_progress.setItem(rows, 3, QTableWidgetItem(service_label))
self.tbl_dl_progress.setCellWidget(rows, 4, status_label)
self.tbl_dl_progress.setCellWidget(rows, 5, actions)
Expand Down Expand Up @@ -259,9 +258,13 @@ def remove_completed_from_download_list(self):
item_id = self.tbl_dl_progress.item(check_row, 0).text()
logger.info(f'Removing Row : {check_row} and mediaid: {item_id}')
if item_id in download_queue:
progress = download_queue[item_id]['gui']["progress_bar"].value()
status = download_queue[item_id]['gui']["status_label"].text().lower()
if progress == 100 or status == self.tr("cancelled"):
status = download_queue[item_id]['gui']["status_label"].text()
if status in (
self.tr("Cancelled"),
self.tr("Downloaded"),
self.tr("Already Exists")
):
logger.info(f'Removing Row : {check_row} and mediaid: {item_id}')
self.tbl_dl_progress.removeRow(check_row)
download_queue.pop(item_id)
else:
Expand Down
2 changes: 1 addition & 1 deletion src/onthespot/otsconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, cfg_path=None):
"rotate_acc_sn": False, # Rotate active account for parsing and downloading tracks
"download_root": os.path.join(os.path.expanduser("~"), "Music", "OnTheSpot"), # Root dir for downloads
"download_delay": 3, # Seconds to wait before next download attempt
"track_path_formatter": "Tracks" + os.path.sep + "{artist}" + os.path.sep + "[{rel_year}] {album}" + os.path.sep + "{track_number}. {name}", # Track path format string
"track_path_formatter": "Tracks" + os.path.sep + "{album_artist}" + os.path.sep + "[{year}] {album}" + os.path.sep + "{track_number}. {name}", # Track path format string
"podcast_path_formatter": "Episodes" + os.path.sep + "{album}" + os.path.sep + "{name}", # Episode path format string
"playlist_path_formatter": "Playlists" + os.path.sep + "{playlist_name} by {playlist_owner}" + os.path.sep + "{name}", # Playlist path format string
"m3u_name_formatter": "M3U" + os.path.sep + "{playlist_name} by {playlist_owner}", # M3U name format string
Expand Down
Loading

0 comments on commit c6f7346

Please sign in to comment.