diff --git a/main.py b/main.py index f99c034..c4cda2f 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ from qo_utils.search import Search from qo_utils import downloader +from pick import pick import argparse +import itertools import re import os import sys @@ -15,7 +17,7 @@ def getArgs(): parser.add_argument("-i", action="store_true", help="run Qo-Dl-curses on URL input mode") parser.add_argument("-q", metavar="int", default=6, - help="FLAC quality (6, 7, 27) (default: 6)") + help="audioquality (5, 6, 7, 27) (default: 6)") parser.add_argument("-l", metavar="int", default=10, help="limit of search results by type (default: 10)") parser.add_argument("-d", metavar="PATH", default='Qobuz Downloads', @@ -43,14 +45,15 @@ def get_id(url): '*-?/|user/library/favorites/)(\w+)', url).group(1) -def searchSelected(Qz, path, start): - q = ['6', '7', '27'] - quality = q[start.quality[1]] - for i in start.Selected: - if start.Types[i[1]]: - downloader.iterateIDs(Qz, start.IDs[i[1]], path, quality, True) - else: - downloader.iterateIDs(Qz, start.IDs[i[1]], path, quality, False) +def searchSelected(Qz, path, albums, ids, types, quality): + q = ['5', '6', '7', '27'] + quality = q[quality[1]] + for alb, id_, type_ in zip(albums, ids, types): + for i in alb: + if type_[i[1]]: + downloader.iterateIDs(Qz, id_[i[1]], path, quality, True) + else: + downloader.iterateIDs(Qz, id_[i[1]], path, quality, False) def fromUrl(Qz, path, link, quality): @@ -64,13 +67,34 @@ def fromUrl(Qz, path, link, quality): def interactive(Qz, path, limit, tracks=True): while True: + Albums, Types, IDs = [], [], [] try: - query = input("\nEnter your search: [Ctrl + c to quit]\n- ") - print('Searching...') - start = Search(Qz, query, limit) - start.getResults(tracks) - start.pickResults() - searchSelected(Qz, path, start) + while True: + query = input("\nEnter your search: [Ctrl + c to quit]\n- ") + print('Searching...') + start = Search(Qz, query, limit) + start.getResults(tracks) + Types.append(start.Types) + IDs.append(start.IDs) + + title = ('Select [space] the item(s) you want to download ' + '(one or more)\nPress Ctrl + c to quit\n') + Selected = pick(start.Total, title, + multiselect=True, min_selection_count=1) + Albums.append(Selected) + + y_n = pick(['Yes', 'No'], 'Items were added to queue to ' + 'be downloaded. Keep searching?') + if y_n[0][0] == 'N': + break + else: + pass + + desc = ('Select [intro] the quality (the quality will be automat' + 'ically\ndowngraded if the selected is not found)') + Qualits = ['320', 'Lossless', 'Hi-res =< 96kHz', 'Hi-Res > 96 kHz'] + quality = pick(Qualits, desc) + searchSelected(Qz, path, Albums, IDs, Types, quality) except KeyboardInterrupt: sys.exit('\nBye') diff --git a/qo_utils/downloader.py b/qo_utils/downloader.py index e376584..e1f1b19 100644 --- a/qo_utils/downloader.py +++ b/qo_utils/downloader.py @@ -36,11 +36,16 @@ def getCover(i, dirn): # Download and tag a file -def downloadItem(dirn, count, parse, meta, album, url, is_track): - fname = '{}/{:02}.flac'.format(dirn, count) +def downloadItem(dirn, count, parse, meta, album, url, is_track, mp3): + if mp3: + fname = '{}/{:02}.mp3'.format(dirn, count) + func = metadata.tag_mp3 + else: + fname = '{}/{:02}.flac'.format(dirn, count) + func = metadata.tag_flac desc = getDesc(parse, meta) req_tqdm(url, fname, desc) - metadata.iterateTag(fname, dirn, meta, album, is_track) + func(fname, dirn, meta, album, is_track) # Iterate over IDs by type calling downloadItem @@ -60,17 +65,20 @@ def iterateIDs(client, id, path, quality, album=False): parse = client.get_track_url(i['id'], quality) url = parse['url'] - if 'sample' not in parse and '.mp3' not in parse: - downloadItem(dirn, count, parse, i, meta, url, False) + if 'sample' not in parse: + if int(quality) == 5: + downloadItem(dirn, count, parse, i, meta, url, False, True) + else: + downloadItem(dirn, count, parse, i, meta, url, False, False) else: - print('Demo or MP3. Skipping') + print('Demo. Skipping') count = count + 1 else: parse = client.get_track_url(id, quality) url = parse['url'] - if 'sample' not in parse and '.mp3' not in parse: + if 'sample' not in parse: meta = client.get_track_meta(id) print('\nDownloading: {}\n'.format(meta['title'])) dirT = (meta['album']['artist']['name'], @@ -79,8 +87,11 @@ def iterateIDs(client, id, path, quality, album=False): dirn = path + '{} - {} [{}]'.format(*dirT) mkDir(dirn) getCover(meta['album']['image']['large'], dirn) - downloadItem(dirn, count, parse, meta, meta, url, True) + if int(quality) == 5: + downloadItem(dirn, count, parse, i, meta, url, False, True) + else: + downloadItem(dirn, count, parse, i, meta, url, False, False) else: - print('Demo or MP3. Skipping') + print('Demo. Skipping') print('\nCompleted\n') diff --git a/qo_utils/metadata.py b/qo_utils/metadata.py index 911b37a..f3b51fc 100644 --- a/qo_utils/metadata.py +++ b/qo_utils/metadata.py @@ -1,9 +1,10 @@ from mutagen.flac import FLAC +from mutagen.mp3 import EasyMP3 from pathvalidate import sanitize_filename import os -def iterateTag(file, path, d, album, istrack=True): +def tag_flac(file, path, d, album, istrack=True): audio = FLAC(file) audio['TITLE'] = d['title'] # TRACK TITLE @@ -26,7 +27,7 @@ def iterateTag(file, path, d, album, istrack=True): audio['ALBUMARTIST'] = d['album']['artist']['name'] # ALBUM ARTIST audio['TRACKTOTAL'] = str(d['album']['tracks_count']) # TRACK TOTAL audio['ALBUM'] = d['album']['title'] # ALBUM TITLE - audio['YEAR'] = d['album']['release_date_original'].split('-')[0] # YEAR + audio['YEAR'] = d['album']['release_date_original'].split('-')[0] else: audio['GENRE'] = ', '.join(album['genres_list']) # GENRE audio['ALBUMARTIST'] = album['artist']['name'] # ALBUM ARTIST @@ -37,3 +38,36 @@ def iterateTag(file, path, d, album, istrack=True): audio.save() title = sanitize_filename(d['title']) os.rename(file, '{}/{:02}. {}.flac'.format(path, d['track_number'], title)) + + +def tag_mp3(file, path, d, album, istrack=True): + audio = EasyMP3(file) + + audio['title'] = d['title'] + audio['tracknumber'] = str(d['track_number']) + try: + audio['composer'] = d['composer']['name'] + except KeyError: + pass + try: + audio['artist'] = d['performer']['name'] # TRACK ARTIST + except KeyError: + if istrack: + audio['artist'] = d['album']['artist']['name'] # TRACK ARTIST + else: + audio['artist'] = album['artist']['name'] + + if istrack: + audio['genre'] = ', '.join(d['album']['genres_list']) # GENRE + audio['albumartist'] = d['album']['artist']['name'] # ALBUM ARTIST + audio['album'] = d['album']['title'] # ALBUM TITLE + audio['date'] = d['album']['release_date_original'].split('-')[0] + else: + audio['GENRE'] = ', '.join(album['genres_list']) # GENRE + audio['albumartist'] = album['artist']['name'] # ALBUM ARTIST + audio['album'] = album['title'] # ALBUM TITLE + audio['date'] = album['release_date_original'].split('-')[0] # YEAR + + audio.save() + title = sanitize_filename(d['title']) + os.rename(file, '{}/{:02}. {}.mp3'.format(path, d['track_number'], title)) diff --git a/qo_utils/search.py b/qo_utils/search.py index 66028c6..39757a6 100644 --- a/qo_utils/search.py +++ b/qo_utils/search.py @@ -1,6 +1,4 @@ import time -import sys -from pick import pick class Search: @@ -41,16 +39,3 @@ class Search: self.itResults(self.Albums) if tracks: self.itResults(self.Tracks) - - def pickResults(self): - title = ('Select [space] the item(s) you want to download ' - '(one or more)\nPress Ctrl + c to quit\n') - quality = ('Select [intro] the quality (the quality will be automat' - 'ically\ndowngraded if the selected is not found)') - Qualitys = ['Lossless', 'Hi-res =< 96kHz', 'Hi-Res > 96 kHz'] - try: - self.Selected = pick(self.Total, title, - multiselect=True, min_selection_count=1) - self.quality = pick(Qualitys, quality) - except KeyboardInterrupt: - sys.exit('Bye')