mirror of
				https://github.com/THIS-IS-NOT-A-BACKUP/zspotify.git
				synced 2025-11-03 21:10:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			288 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from librespot.audio.decoders import AudioQuality
 | 
						|
from tabulate import tabulate
 | 
						|
import os
 | 
						|
 | 
						|
from album import download_album, download_artist_albums
 | 
						|
from const import TRACK, NAME, ID, ARTIST, ARTISTS, ITEMS, TRACKS, EXPLICIT, ALBUM, ALBUMS, \
 | 
						|
    OWNER, PLAYLIST, PLAYLISTS, DISPLAY_NAME
 | 
						|
from playlist import get_playlist_songs, get_playlist_info, download_from_user_playlist, download_playlist
 | 
						|
from podcast import download_episode, get_show_episodes
 | 
						|
from termoutput import Printer, PrintChannel
 | 
						|
from track import download_track, get_saved_tracks
 | 
						|
from utils import splash, split_input, regex_input_for_urls
 | 
						|
from zspotify import ZSpotify
 | 
						|
 | 
						|
SEARCH_URL = 'https://api.spotify.com/v1/search'
 | 
						|
 | 
						|
 | 
						|
def client(args) -> None:
 | 
						|
    """ Connects to spotify to perform query's and get songs to download """
 | 
						|
    ZSpotify(args)
 | 
						|
 | 
						|
    Printer.print(PrintChannel.SPLASH, splash())
 | 
						|
 | 
						|
    if ZSpotify.check_premium():
 | 
						|
        Printer.print(PrintChannel.SPLASH, '[ DETECTED PREMIUM ACCOUNT - USING VERY_HIGH QUALITY ]\n\n')
 | 
						|
        ZSpotify.DOWNLOAD_QUALITY = AudioQuality.VERY_HIGH
 | 
						|
    else:
 | 
						|
        Printer.print(PrintChannel.SPLASH, '[ DETECTED FREE ACCOUNT - USING HIGH QUALITY ]\n\n')
 | 
						|
        ZSpotify.DOWNLOAD_QUALITY = AudioQuality.HIGH
 | 
						|
 | 
						|
    if args.download:
 | 
						|
        urls = []
 | 
						|
        filename = args.download
 | 
						|
        if os.path.exists(filename):
 | 
						|
            with open(filename, 'r', encoding='utf-8') as file:
 | 
						|
                urls.extend([line.strip() for line in file.readlines()])
 | 
						|
 | 
						|
            download_from_urls(urls)
 | 
						|
 | 
						|
        else:
 | 
						|
            Printer.print(PrintChannel.ERRORS, f'File {filename} not found.\n')
 | 
						|
 | 
						|
    if args.urls:
 | 
						|
        download_from_urls(args.urls)
 | 
						|
 | 
						|
    if args.playlist:
 | 
						|
        download_from_user_playlist()
 | 
						|
 | 
						|
    if args.liked_songs:
 | 
						|
        for song in get_saved_tracks():
 | 
						|
            if not song[TRACK][NAME] or not song[TRACK][ID]:
 | 
						|
                Printer.print(PrintChannel.SKIPS, '###   SKIPPING:  SONG DOES NOT EXIST ON SPOTIFY ANYMORE   ###' + "\n")
 | 
						|
            else:
 | 
						|
                download_track('liked', song[TRACK][ID])
 | 
						|
 | 
						|
    if args.search_spotify:
 | 
						|
        search_text = ''
 | 
						|
        while len(search_text) == 0:
 | 
						|
            search_text = input('Enter search or URL: ')
 | 
						|
 | 
						|
        if not download_from_urls([search_text]):
 | 
						|
            search(search_text)
 | 
						|
 | 
						|
def download_from_urls(urls: list[str]) -> bool:
 | 
						|
    """ Downloads from a list of spotify urls """
 | 
						|
    download = False
 | 
						|
 | 
						|
    for spotify_url in urls:
 | 
						|
        track_id, album_id, playlist_id, episode_id, show_id, artist_id = regex_input_for_urls(
 | 
						|
            spotify_url)
 | 
						|
 | 
						|
        if track_id is not None:
 | 
						|
            download = True
 | 
						|
            download_track('single', track_id)
 | 
						|
        elif artist_id is not None:
 | 
						|
            download = True
 | 
						|
            download_artist_albums(artist_id)
 | 
						|
        elif album_id is not None:
 | 
						|
            download = True
 | 
						|
            download_album(album_id)
 | 
						|
        elif playlist_id is not None:
 | 
						|
            download = True
 | 
						|
            playlist_songs = get_playlist_songs(playlist_id)
 | 
						|
            name, _ = get_playlist_info(playlist_id)
 | 
						|
            enum = 1
 | 
						|
            char_num = len(str(len(playlist_songs)))
 | 
						|
            for song in playlist_songs:
 | 
						|
                if not song[TRACK][NAME] or not song[TRACK][ID]:
 | 
						|
                    Printer.print(PrintChannel.SKIPS, '###   SKIPPING:  SONG DOES NOT EXIST ON SPOTIFY ANYMORE   ###' + "\n")
 | 
						|
                else:
 | 
						|
                    download_track('playlist', song[TRACK][ID], extra_keys=
 | 
						|
                    {
 | 
						|
                        'playlist_song_name': song[TRACK][NAME],
 | 
						|
                        'playlist': name,
 | 
						|
                        'playlist_num': str(enum).zfill(char_num),
 | 
						|
                        'playlist_id': playlist_id,
 | 
						|
                        'playlist_track_id': song[TRACK][ID]
 | 
						|
                    })
 | 
						|
                    enum += 1
 | 
						|
        elif episode_id is not None:
 | 
						|
            download = True
 | 
						|
            download_episode(episode_id)
 | 
						|
        elif show_id is not None:
 | 
						|
            download = True
 | 
						|
            for episode in get_show_episodes(show_id):
 | 
						|
                download_episode(episode)
 | 
						|
 | 
						|
    return download
 | 
						|
 | 
						|
 | 
						|
def search(search_term):
 | 
						|
    """ Searches Spotify's API for relevant data """
 | 
						|
    params = {'limit': '10',
 | 
						|
              'offset': '0',
 | 
						|
              'q': search_term,
 | 
						|
              'type': 'track,album,artist,playlist'}
 | 
						|
 | 
						|
    # Parse args
 | 
						|
    splits = search_term.split()
 | 
						|
    for split in splits:
 | 
						|
        index = splits.index(split)
 | 
						|
 | 
						|
        if split[0] == '-' and len(split) > 1:
 | 
						|
            if len(splits)-1 == index:
 | 
						|
                raise IndexError('No parameters passed after option: {}\n'.
 | 
						|
                                 format(split))
 | 
						|
 | 
						|
        if split == '-l' or split == '-limit':
 | 
						|
            try:
 | 
						|
                int(splits[index+1])
 | 
						|
            except ValueError:
 | 
						|
                raise ValueError('Paramater passed after {} option must be an integer.\n'.
 | 
						|
                                 format(split))
 | 
						|
            if int(splits[index+1]) > 50:
 | 
						|
                raise ValueError('Invalid limit passed. Max is 50.\n')
 | 
						|
            params['limit'] = splits[index+1]
 | 
						|
 | 
						|
        if split == '-t' or split == '-type':
 | 
						|
 | 
						|
            allowed_types = ['track', 'playlist', 'album', 'artist']
 | 
						|
            passed_types = []
 | 
						|
            for i in range(index+1, len(splits)):
 | 
						|
                if splits[i][0] == '-':
 | 
						|
                    break
 | 
						|
 | 
						|
                if splits[i] not in allowed_types:
 | 
						|
                    raise ValueError('Parameters passed after {} option must be from this list:\n{}'.
 | 
						|
                                     format(split, '\n'.join(allowed_types)))
 | 
						|
 | 
						|
                passed_types.append(splits[i])
 | 
						|
            params['type'] = ','.join(passed_types)
 | 
						|
 | 
						|
    if len(params['type']) == 0:
 | 
						|
        params['type'] = 'track,album,artist,playlist'
 | 
						|
 | 
						|
    # Clean search term
 | 
						|
    search_term_list = []
 | 
						|
    for split in splits:
 | 
						|
        if split[0] == "-":
 | 
						|
            break
 | 
						|
        search_term_list.append(split)
 | 
						|
    if not search_term_list:
 | 
						|
        raise ValueError("Invalid query.")
 | 
						|
    params["q"] = ' '.join(search_term_list)
 | 
						|
 | 
						|
    resp = ZSpotify.invoke_url_with_params(SEARCH_URL, **params)
 | 
						|
 | 
						|
    counter = 1
 | 
						|
    dics = []
 | 
						|
 | 
						|
    total_tracks = 0
 | 
						|
    if TRACK in params['type'].split(','):
 | 
						|
        tracks = resp[TRACKS][ITEMS]
 | 
						|
        if len(tracks) > 0:
 | 
						|
            print('###  TRACKS  ###')
 | 
						|
            track_data = []
 | 
						|
            for track in tracks:
 | 
						|
                if track[EXPLICIT]:
 | 
						|
                    explicit = '[E]'
 | 
						|
                else:
 | 
						|
                    explicit = ''
 | 
						|
 | 
						|
                track_data.append([counter, f'{track[NAME]} {explicit}',
 | 
						|
                                  ','.join([artist[NAME] for artist in track[ARTISTS]])])
 | 
						|
                dics.append({
 | 
						|
                    ID: track[ID],
 | 
						|
                    NAME: track[NAME],
 | 
						|
                    'type': TRACK,
 | 
						|
                })
 | 
						|
 | 
						|
                counter += 1
 | 
						|
            total_tracks = counter - 1
 | 
						|
            print(tabulate(track_data, headers=[
 | 
						|
                  'S.NO', 'Name', 'Artists'], tablefmt='pretty'))
 | 
						|
            print('\n')
 | 
						|
            del tracks
 | 
						|
            del track_data
 | 
						|
 | 
						|
    total_albums = 0
 | 
						|
    if ALBUM in params['type'].split(','):
 | 
						|
        albums = resp[ALBUMS][ITEMS]
 | 
						|
        if len(albums) > 0:
 | 
						|
            print('###  ALBUMS  ###')
 | 
						|
            album_data = []
 | 
						|
            for album in albums:
 | 
						|
                album_data.append([counter, album[NAME],
 | 
						|
                                  ','.join([artist[NAME] for artist in album[ARTISTS]])])
 | 
						|
                dics.append({
 | 
						|
                    ID: album[ID],
 | 
						|
                    NAME: album[NAME],
 | 
						|
                    'type': ALBUM,
 | 
						|
                })
 | 
						|
 | 
						|
                counter += 1
 | 
						|
            total_albums = counter - total_tracks - 1
 | 
						|
            print(tabulate(album_data, headers=[
 | 
						|
                  'S.NO', 'Album', 'Artists'], tablefmt='pretty'))
 | 
						|
            print('\n')
 | 
						|
            del albums
 | 
						|
            del album_data
 | 
						|
 | 
						|
    total_artists = 0
 | 
						|
    if ARTIST in params['type'].split(','):
 | 
						|
        artists = resp[ARTISTS][ITEMS]
 | 
						|
        if len(artists) > 0:
 | 
						|
            print('###  ARTISTS  ###')
 | 
						|
            artist_data = []
 | 
						|
            for artist in artists:
 | 
						|
                artist_data.append([counter, artist[NAME]])
 | 
						|
                dics.append({
 | 
						|
                    ID: artist[ID],
 | 
						|
                    NAME: artist[NAME],
 | 
						|
                    'type': ARTIST,
 | 
						|
                })
 | 
						|
                counter += 1
 | 
						|
            total_artists = counter - total_tracks - total_albums - 1
 | 
						|
            print(tabulate(artist_data, headers=[
 | 
						|
                  'S.NO', 'Name'], tablefmt='pretty'))
 | 
						|
            print('\n')
 | 
						|
            del artists
 | 
						|
            del artist_data
 | 
						|
 | 
						|
    total_playlists = 0
 | 
						|
    if PLAYLIST in params['type'].split(','):
 | 
						|
        playlists = resp[PLAYLISTS][ITEMS]
 | 
						|
        if len(playlists) > 0:
 | 
						|
            print('###  PLAYLISTS  ###')
 | 
						|
            playlist_data = []
 | 
						|
            for playlist in playlists:
 | 
						|
                playlist_data.append(
 | 
						|
                    [counter, playlist[NAME], playlist[OWNER][DISPLAY_NAME]])
 | 
						|
                dics.append({
 | 
						|
                    ID: playlist[ID],
 | 
						|
                    NAME: playlist[NAME],
 | 
						|
                    'type': PLAYLIST,
 | 
						|
                })
 | 
						|
                counter += 1
 | 
						|
            total_playlists = counter - total_artists - total_tracks - total_albums - 1
 | 
						|
            print(tabulate(playlist_data, headers=[
 | 
						|
                  'S.NO', 'Name', 'Owner'], tablefmt='pretty'))
 | 
						|
            print('\n')
 | 
						|
            del playlists
 | 
						|
            del playlist_data
 | 
						|
 | 
						|
    if total_tracks + total_albums + total_artists + total_playlists == 0:
 | 
						|
        print('NO RESULTS FOUND - EXITING...')
 | 
						|
    else:
 | 
						|
        selection = ''
 | 
						|
        print('> SELECT A DOWNLOAD OPTION BY ID')
 | 
						|
        print('> SELECT A RANGE BY ADDING A DASH BETWEEN BOTH ID\'s')
 | 
						|
        print('> OR PARTICULAR OPTIONS BY ADDING A COMMA BETWEEN ID\'s\n')
 | 
						|
        while len(selection) == 0:
 | 
						|
            selection = str(input('ID(s): '))
 | 
						|
        inputs = split_input(selection)
 | 
						|
        for pos in inputs:
 | 
						|
            position = int(pos)
 | 
						|
            for dic in dics:
 | 
						|
                print_pos = dics.index(dic) + 1
 | 
						|
                if print_pos == position:
 | 
						|
                    if dic['type'] == TRACK:
 | 
						|
                        download_track('single', dic[ID])
 | 
						|
                    elif dic['type'] == ALBUM:
 | 
						|
                        download_album(dic[ID])
 | 
						|
                    elif dic['type'] == ARTIST:
 | 
						|
                        download_artist_albums(dic[ID])
 | 
						|
                    else:
 | 
						|
                        download_playlist(dic)
 |