Revert "Merge branch 'main' into argument-parsing"

This reverts commit e7b3f5c4bd, reversing
changes made to 95f0dc8edf.
This commit is contained in:
el-gringo-alto 2021-10-28 02:25:57 -04:00
parent 47bd178501
commit 7412abcee5
9 changed files with 45 additions and 137 deletions

View File

@ -16,8 +16,8 @@ jobs:
- name: Setup Pylint
run: |
python -m pip install --upgrade pip
pip install pylint pylint-exit
pip install pylint
pip install -r requirements.txt
- name: Run Pylint
run: |
pylint $(git ls-files '*.py') || pylint-exit $?
pylint $(git ls-files '*.py')

View File

@ -1,10 +1,4 @@
## **Changelog:**
**v2.4 (27 Oct 20212):**
- Added realtime downloading support to avoid account suspensions.
- Fix for downloading by artist.
- Replace audio conversion method for better quality.
- Fix bug when automatically setting audio bitrate.
**v2.3 (25 Oct 2021):**
- Moved changelog to seperate file.
- Added argument parsing in search function (query results limit and query result types).

View File

@ -67,7 +67,6 @@ Create and run a container from the image:
**There have been 2-3 reports from users who received account bans from Spotify for using this tool**.
We recommend using ZSpotify with a burner account.
Alternatively, there is a configuration option labled ```DOWNLOAD_REAL_TIME```, this limits the download speed to the duration of the song being downloaded thus not appearing suspicious to Spotify.
This option is much slower and is only recommended for premium users who wish to download songs in 320kbps without buying premium on a burner account.

View File

@ -1,8 +1,6 @@
ffmpy
git+https://github.com/kokarare1212/librespot-python
music_tag
Pillow
protobuf
pydub
tabulate
Pillow
tqdm
tabulate

View File

@ -33,7 +33,7 @@ def get_album_name(album_id):
def get_artist_albums(artist_id):
""" Returns artist's albums """
resp = ZSpotify.invoke_url(f'{ARTIST_URL}/{artist_id}/albums?include_groups=album%2Csingle')
resp = ZSpotify.invoke_url(f'{ARTIST_URL}/{artist_id}/albums')
# Return a list each album's id
album_ids = [resp[ITEMS][i][ID] for i in range(len(resp[ITEMS]))]
# Recursive requests to get all albums including singles an EPs

View File

@ -96,39 +96,14 @@ CHUNK_SIZE = 'CHUNK_SIZE'
SPLIT_ALBUM_DISCS = 'SPLIT_ALBUM_DISCS'
DOWNLOAD_REAL_TIME = 'DOWNLOAD_REAL_TIME'
BITRATE = 'BITRATE'
CODEC_MAP = {
'aac': 'aac',
'fdk_aac': 'libfdk_aac',
'm4a': 'aac',
'mp3': 'libmp3lame',
'ogg': 'copy',
'opus': 'libopus',
'vorbis': 'copy',
}
EXT_MAP = {
'aac': 'm4a',
'fdk_aac': 'm4a',
'm4a': 'm4a',
'mp3': 'mp3',
'ogg': 'ogg',
'opus': 'ogg',
'vorbis': 'ogg',
}
CONFIG_DEFAULT_SETTINGS = {
'ROOT_PATH': '../ZSpotify Music/',
'ROOT_PODCAST_PATH': '../ZSpotify Podcasts/',
'SKIP_EXISTING_FILES': True,
'DOWNLOAD_FORMAT': 'ogg',
'DOWNLOAD_FORMAT': 'mp3',
'FORCE_PREMIUM': False,
'ANTI_BAN_WAIT_TIME': 1,
'OVERRIDE_AUTO_WAIT': False,
'CHUNK_SIZE': 50000,
'SPLIT_ALBUM_DISCS': False,
'DOWNLOAD_REAL_TIME': False
'SPLIT_ALBUM_DISCS': False
}

View File

@ -52,12 +52,10 @@ def download_playlist(playlist):
playlist_songs = [song for song in get_playlist_songs(playlist[ID]) if song[TRACK][ID]]
p_bar = tqdm(playlist_songs, unit='song', total=len(playlist_songs), unit_scale=True)
enum = 1
for song in p_bar:
download_track(song[TRACK][ID], sanitize_data(playlist[NAME].strip()) + '/',
prefix=True, prefix_value=str(enum) ,disable_progressbar=True)
disable_progressbar=True)
p_bar.set_description(song[TRACK][NAME])
enum += 1
def download_from_user_playlist():

View File

@ -5,11 +5,11 @@ from librespot.audio.decoders import VorbisOnlyAudioQuality
from librespot.metadata import EpisodeId
from tqdm import tqdm
from const import (CHUNK_SIZE, ERROR, ID, ITEMS, NAME, ROOT_PODCAST_PATH, SHOW,
SKIP_EXISTING_FILES)
from utils import create_download_directory, sanitize_data
from const import NAME, ERROR, SHOW, ITEMS, ID, ROOT_PODCAST_PATH, CHUNK_SIZE
from utils import sanitize_data, create_download_directory, MusicFormat
from zspotify import ZSpotify
EPISODE_INFO_URL = 'https://api.spotify.com/v1/episodes'
SHOWS_URL = 'https://api.spotify.com/v1/shows'
@ -50,32 +50,12 @@ def download_episode(episode_id) -> None:
episode_id = EpisodeId.from_base62(episode_id)
stream = ZSpotify.get_content_stream(episode_id, ZSpotify.DOWNLOAD_QUALITY)
download_directory = os.path.join(
os.path.dirname(__file__),
ZSpotify.get_config(ROOT_PODCAST_PATH),
extra_paths,
)
download_directory = os.path.realpath(download_directory)
download_directory = os.path.dirname(__file__) + ZSpotify.get_config(ROOT_PODCAST_PATH) + extra_paths
create_download_directory(download_directory)
total_size = stream.input_stream.size
filepath = os.path.join(download_directory, f"{filename}.ogg")
if (
os.path.isfile(filepath)
and os.path.getsize(filepath) == total_size
and ZSpotify.get_config(SKIP_EXISTING_FILES)
):
print(
"\n### SKIPPING:",
podcast_name,
"-",
episode_name,
"(EPISODE ALREADY EXISTS) ###",
)
return
with open(filepath, 'wb') as file, tqdm(
with open(download_directory + filename + MusicFormat.OGG.value,
'wb') as file, tqdm(
desc=filename,
total=total_size,
unit='B',

View File

@ -4,14 +4,14 @@ from typing import Any, Tuple, List
from librespot.audio.decoders import AudioQuality
from librespot.metadata import TrackId
from ffmpy import FFmpeg
from pydub import AudioSegment
from tqdm import tqdm
from const import TRACKS, ALBUM, NAME, ITEMS, DISC_NUMBER, TRACK_NUMBER, IS_PLAYABLE, ARTISTS, IMAGES, URL, \
RELEASE_DATE, ID, TRACKS_URL, SAVED_TRACKS_URL, SPLIT_ALBUM_DISCS, ROOT_PATH, DOWNLOAD_FORMAT, CHUNK_SIZE, \
SKIP_EXISTING_FILES, ANTI_BAN_WAIT_TIME, OVERRIDE_AUTO_WAIT, BITRATE, CODEC_MAP, EXT_MAP, DOWNLOAD_REAL_TIME
from utils import sanitize_data, set_audio_tags, set_music_thumbnail, create_download_directory
SKIP_EXISTING_FILES, ANTI_BAN_WAIT_TIME, OVERRIDE_AUTO_WAIT
from utils import sanitize_data, set_audio_tags, set_music_thumbnail, create_download_directory, \
MusicFormat
from zspotify import ZSpotify
@ -72,7 +72,7 @@ def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='',
) else f'{prefix_value} - {song_name}'
filename = os.path.join(
download_directory, f'{song_name}.{EXT_MAP.get(ZSpotify.get_config(DOWNLOAD_FORMAT))}')
download_directory, f'{song_name}.{ZSpotify.get_config(DOWNLOAD_FORMAT)}')
except Exception as e:
print('### SKIPPING SONG - FAILED TO QUERY METADATA ###')
@ -103,17 +103,11 @@ def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='',
unit_divisor=1024,
disable=disable_progressbar
) as p_bar:
for chunk in range(int(total_size / ZSpotify.get_config(CHUNK_SIZE)) + 1):
data = stream.input_stream.stream().read(ZSpotify.get_config(CHUNK_SIZE))
if data == b'':
break
p_bar.update(file.write(data))
if ZSpotify.get_config(DOWNLOAD_REAL_TIME):
if chunk == 0:
pause = get_segment_duration(p_bar)
if pause:
time.sleep(pause)
for _ in range(int(total_size / ZSpotify.get_config(CHUNK_SIZE)) + 1):
p_bar.update(file.write(
stream.input_stream.stream().read(ZSpotify.get_config(CHUNK_SIZE))))
if ZSpotify.get_config(DOWNLOAD_FORMAT) == 'mp3':
convert_audio_format(filename)
set_audio_tags(filename, artists, name, album_name,
release_year, disc_number, track_number)
@ -129,44 +123,14 @@ def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='',
os.remove(filename)
def get_segment_duration(segment):
""" Returns playback duration of given audio segment """
sound = AudioSegment(
data = segment,
sample_width = 2,
frame_rate = 44100,
channels = 2
)
duration = len(sound) / 5000
return duration
def convert_audio_format(filename) -> None:
""" Converts raw audio into playable file """
temp_filename = f'{os.path.splitext(filename)[0]}.tmp'
os.replace(filename, temp_filename)
download_format = ZSpotify.get_config(DOWNLOAD_FORMAT)
file_codec = CODEC_MAP.get(download_format, "copy")
if file_codec != 'copy':
bitrate = ZSpotify.get_config(BITRATE)
if not bitrate:
""" Converts raw audio into playable mp3 """
# print('### CONVERTING TO ' + MUSIC_FORMAT.upper() + ' ###')
raw_audio = AudioSegment.from_file(filename, format=MusicFormat.OGG.value,
frame_rate=44100, channels=2, sample_width=2)
if ZSpotify.DOWNLOAD_QUALITY == AudioQuality.VERY_HIGH:
bitrate = '320k'
else:
bitrate = '160k'
else:
bitrate = None
output_params = ['-c:a', file_codec]
if bitrate:
output_params += ['-b:a', bitrate]
ff_m = FFmpeg(
global_options=['-y', '-hide_banner', '-loglevel error'],
inputs={temp_filename: None},
outputs={filename: output_params}
)
ff_m.run()
if os.path.exists(temp_filename):
os.remove(temp_filename)
raw_audio.export(filename, format=ZSpotify.get_config(
DOWNLOAD_FORMAT), bitrate=bitrate)