Housekeeping + Minor bugfixes

Fixed: #186, #188, #189

Cleaned up lingering `.format()`s and replaced with appropriate f-strings.

Updated project structure to slightly more modern standards.
master
AnthonyF 2021-12-09 21:18:42 -05:00
parent 3019b26c46
commit cf9d43fed2
11 changed files with 83 additions and 63 deletions

View File

@ -65,15 +65,15 @@ from bandcamp_dl.__init__ import __version__
def main():
arguments = docopt(__doc__, version='bandcamp-dl {}'.format(__version__))
arguments = docopt(__doc__, version=f'bandcamp-dl {__version__}')
if arguments['--debug']:
logging.basicConfig(level=logging.DEBUG)
bandcamp = Bandcamp()
basedir = arguments['--base-dir'] or os.getcwd()
session_file = "{}/{}.not.finished".format(basedir, __version__)
basedir = arguments['--base-dir'] or os.path.expanduser('~')
session_file = f"{basedir}/{__version__}.not.finished"
if os.path.isfile(session_file) and arguments['URL'] is None:
with open(session_file, "r") as f:
@ -92,24 +92,25 @@ def main():
exit()
else:
urls = arguments['URL']
album_list = []
for url in urls:
logging.debug("\n\tURL: {}".format(url))
# url is now a list of URLs. So lets make an albumList and append each parsed album to it.
albumList = []
for url in urls:
albumList.append(bandcamp.parse(url, not arguments['--no-art'], arguments['--embed-lyrics'], arguments['--debug']))
album_list.append(
bandcamp.parse(url, not arguments['--no-art'], arguments['--embed-lyrics'], arguments['--debug']))
# url is now a list of URLs. So lets make an album_list and append each parsed album to it.
for album in albumList:
for album in album_list:
logging.debug(" Album data:\n\t{}".format(album))
for album in albumList:
for album in album_list:
if arguments['--full-album'] and not album['full']:
print("Full album not available. Skipping ", album['title'], " ...")
albumList.remove(album) # Remove not-full albums BUT continue with the rest of the albums.
album_list.remove(album) # Remove not-full albums BUT continue with the rest of the albums.
if arguments['URL'] or arguments['--artist']:
logging.debug("Preparing download process..")
for album in albumList:
for album in album_list:
bandcamp_downloader = BandcampDownloader(arguments['--template'], basedir, arguments['--overwrite'],
arguments['--embed-lyrics'], arguments['--group'],
arguments['--embed-art'], arguments['--no-slugify'],

View File

@ -12,10 +12,12 @@ from bandcamp_dl.__init__ import __version__
class Bandcamp:
def __init__(self):
self.headers = {'User-Agent': 'bandcamp-dl/{} (https://github.com/iheanyi/bandcamp-dl)'.format(__version__)}
self.headers = {'User-Agent': f'bandcamp-dl/{__version__} (https://github.com/iheanyi/bandcamp-dl)'}
self.soup = None
self.tracks = None
def parse(self, url: str, art: bool=True, lyrics: bool=False, debugging: bool=False) -> dict or None:
"""Requests the page, cherry picks album info
def parse(self, url: str, art: bool = True, lyrics: bool = False, debugging: bool = False) -> dict or None:
"""Requests the page, cherry-picks album info
:param url: album/track url
:param art: if True download album art
@ -56,7 +58,7 @@ class Bandcamp:
album_title = page_json['trackinfo'][0]['title']
try:
label = page_json['item_sellers']['{}'.format(page_json['current']['selling_band_id'])]['name']
label = page_json['item_sellers'][f'{page_json["current"]["selling_band_id"]}']['name']
except KeyError:
label = None
@ -71,10 +73,14 @@ class Bandcamp:
"url": url
}
artist_url = page_json['url'].rpartition('/album/')[0]
if "track" in page_json['url']:
artist_url = page_json['url'].rpartition('/track/')[0]
else:
artist_url = page_json['url'].rpartition('/album/')[0]
for track in self.tracks:
if lyrics:
track['lyrics'] = self.get_track_lyrics("{}{}#lyrics".format(artist_url, track['title_link']))
track['lyrics'] = self.get_track_lyrics(f"{artist_url}{track['title_link']}#lyrics")
if track['file'] is not None:
track = self.get_track_metadata(track)
album['tracks'].append(track)
@ -84,7 +90,7 @@ class Bandcamp:
album['art'] = self.get_album_art()
logging.debug(" Album generated..")
logging.debug(" Album URL: {}".format(album['url']))
logging.debug(f" Album URL: {album['url']}")
return album
@ -153,7 +159,7 @@ class Bandcamp:
:param page_type: Type of page album/track
:return: url as str
"""
return "http://{0}.bandcamp.com/{1}/{2}".format(artist, page_type, slug)
return f"http://{artist}.bandcamp.com/{page_type}/{slug}"
def get_album_art(self) -> str:
"""Find and retrieve album art url from page

View File

@ -29,7 +29,7 @@ class BandcampDownloader:
:param directory: download location
:param overwrite: if True overwrite existing files
"""
self.headers = {'User-Agent': 'bandcamp-dl/{} (https://github.com/iheanyi/bandcamp-dl)'.format(__version__)}
self.headers = {'User-Agent': f'bandcamp-dl/{__version__} (https://github.com/iheanyi/bandcamp-dl)'}
self.session = requests.Session()
if type(urls) is str:
@ -102,10 +102,12 @@ class BandcampDownloader:
else:
path = path.replace("%{track}", str(track['track']).zfill(2))
path = u"{0}/{1}.{2}".format(self.directory, path, "mp3")
# Double check that the old issue in Python 2 with unicode strings isn't a problem with f-strings
# Otherwise find an alternative to u'STRING'
path = f"{self.directory}/{path}.mp3"
logging.debug(" filepath/trackname generated..")
logging.debug("\n\tPath: {}".format(path))
logging.debug(f"\n\tPath: {path}")
return path
@staticmethod
@ -116,7 +118,7 @@ class BandcampDownloader:
:return: directory path
"""
directory = os.path.dirname(filename)
logging.debug(" Directory:\n\t{}".format(directory))
logging.debug(f" Directory:\n\t{directory}")
logging.debug(" Directory doesn't exist, creating..")
if not os.path.exists(directory):
os.makedirs(directory)
@ -144,11 +146,12 @@ class BandcampDownloader:
self.num_tracks = len(album['tracks'])
self.track_num = track_index + 1
filepath = self.template_to_path(track_meta, self.ascii_only, self.ok_chars, self.space_char, self.keep_space, self.keep_upper) + ".tmp"
filepath = self.template_to_path(track_meta, self.ascii_only, self.ok_chars, self.space_char,
self.keep_space, self.keep_upper) + ".tmp"
filename = filepath.rsplit('/', 1)[1]
dirname = self.create_directory(filepath)
logging.debug(" Current file:\n\t{}".format(filepath))
logging.debug(f" Current file:\n\t{filepath}")
if album['art'] and not os.path.exists(dirname + "/cover.jpg"):
try:
@ -180,7 +183,7 @@ class BandcampDownloader:
# break out of the try/except and move on to the next file
break
elif os.path.exists(filepath[:-4]) and self.overwrite is not True:
print("File: {} already exists and is complete, skipping..".format(filename[:-4]))
print(f"File: {filename[:-4]} already exists and is complete, skipping..")
skip = True
break
with open(filepath, "wb") as f:
@ -194,13 +197,11 @@ class BandcampDownloader:
if not self.debugging:
done = int(50 * dl / file_length)
print_clean(
"\r({}/{}) [{}{}] :: Downloading: {}".format(self.track_num, self.num_tracks,
"=" * done, " " * (50 - done),
filename[:-8]))
f'\r({self.track_num}/{self.num_tracks}) [{"=" * done}{" " * (50 - done)}] :: Downloading: {filename[:-8]}')
local_size = os.path.getsize(filepath)
# if the local filesize before encoding doesn't match the remote filesize redownload
if local_size != file_length and attempts != 3:
print("{} is incomplete, retrying..".format(filename))
print(f"{filename} is incomplete, retrying..")
continue
# if the maximum number of retry attempts is reached give up and move on
elif attempts == 3:
@ -218,8 +219,8 @@ class BandcampDownloader:
if skip is False:
self.write_id3_tags(filepath, track_meta)
if os.path.isfile("{}/{}.not.finished".format(self.directory, __version__)):
os.remove("{}/{}.not.finished".format(self.directory, __version__))
if os.path.isfile(f"{self.directory}/{__version__}.not.finished"):
os.remove(f"{self.directory}/{__version__}.not.finished")
# Remove album art image as it is embedded
if self.embed_art:
@ -238,7 +239,7 @@ class BandcampDownloader:
filename = filepath.rsplit('/', 1)[1][:-8]
if not self.debugging:
print_clean("\r({}/{}) [{}] :: Encoding: {}".format(self.track_num, self.num_tracks, "=" * 50, filename))
print_clean(f'\r({self.track_num}/{self.num_tracks}) [{"=" * 50}] :: Encoding: {filename}')
audio = MP3(filepath)
audio.delete()
@ -267,7 +268,7 @@ class BandcampDownloader:
audio.save()
logging.debug(" Encoding process finished..")
logging.debug(" Renaming:\n\t{} -to-> {}".format(filepath, filepath[:-4]))
logging.debug(f" Renaming:\n\t{filepath} -to-> {filepath[:-4]}")
try:
os.rename(filepath, filepath[:-4])
@ -276,4 +277,4 @@ class BandcampDownloader:
os.rename(filepath, filepath[:-4])
if not self.debugging:
print_clean("\r({}/{}) [{}] :: Finished: {}".format(self.track_num, self.num_tracks, "=" * 50, filename))
print_clean(f'\r({self.track_num}/{self.num_tracks}) [{"=" * 50}] :: Finished: {filename}')

View File

@ -1,10 +1,10 @@
import logging
import demjson
import demjson3
class BandcampJSON:
def __init__(self, body, debugging: bool=False):
def __init__(self, body, debugging: bool = False):
self.body = body
self.json_data = []
@ -41,6 +41,7 @@ class BandcampJSON:
"""Convert JavaScript dictionary to JSON"""
logging.debug(" Converting JS to JSON..")
# Decode with demjson first to reformat keys and lists
decoded_js = demjson.decode(js_data)
decoded_js = demjson3.decode(js_data)
# Encode to make valid JSON, add to list of JSON strings
return demjson.encode(decoded_js)
encoded_json = demjson3.encode(decoded_js)
return demjson3.encode(decoded_js)

View File

@ -1,8 +1,8 @@
beautifulsoup4==4.6.0
demjson==2.2.4
beautifulsoup4==4.10.0
demjson3==3.0.5
docopt==0.6.2
mutagen==1.38
requests==2.18.4
unicode-slugify==0.1.3
mock==2.0.0
chardet==3.0.4
mutagen==1.45.1
requests==2.26.0
unicode-slugify==0.1.5
mock==4.0.3
chardet==4.0.0

View File

@ -3,5 +3,4 @@ import shutil
def print_clean(msg):
terminal_size = shutil.get_terminal_size()
msg_length = len(msg)
print("{}{}".format(msg, " " * (int(terminal_size[0]) - msg_length)), end='')
print(f'{msg}{" " * (int(terminal_size[0]) - len(msg))}', end='')

View File

@ -27,7 +27,7 @@ def parse_headers(fp, _class=http.client.HTTPMessage):
raise http.client.LineTooLong("header line")
headers.append(line)
if len(headers) > http.client._MAXHEADERS:
raise HTTPException("got more than {} headers".format(http.client._MAXHEADERS))
raise HTTPException(f"got more than {http.client._MAXHEADERS} headers")
if line in (b'\r\n', b'\n', b''):
break

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=43.0.0", "wheel"]
build-backend = "setuptools.build_meta"

View File

@ -1,10 +1,10 @@
--index-url https://pypi.python.org/simple/
beautifulsoup4==4.9.3
demjson==2.2.4
beautifulsoup4==4.10.0
demjson3==3.0.5
docopt==0.6.2
mutagen==1.45.1
requests==2.25.1
unicode-slugify==0.1.3
requests==2.26.0
unicode-slugify==0.1.5
mock==4.0.3
chardet==4.0.0

View File

@ -2,4 +2,4 @@
universal = 0
[metadata]
license_file = LICENSE
license_files = LICENSE

View File

@ -1,20 +1,19 @@
from setuptools import setup, find_packages
from codecs import open
from os import path
import sys
import pathlib
appversion = "0.0.10"
appversion = "0.0.11-dev"
here = path.abspath(path.dirname(__file__))
here = pathlib.Path(__file__).parent.resolve()
with open(here + '/bandcamp_dl/__init__.py', 'w') as initpy:
initpy.write('__version__ = "{}"'.format(appversion))
with open(f'{here}/bandcamp_dl/__init__.py', 'w') as initpy:
initpy.write(f'__version__ = "{appversion}"')
setup(
name='bandcamp-downloader',
version=appversion,
description='bandcamp-dl downloads albums and tracks from Bandcamp for you',
long_description=open('README.rst').read(),
long_description_content_type='text/x-rst',
url='https://github.com/iheanyi/bandcamp-dl',
author='Iheanyi Ekechukwu',
author_email='iekechukwu@gmail.com',
@ -28,13 +27,19 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3 :: Only',
],
keywords=['bandcamp', 'downloader', 'music', 'cli', 'albums', 'dl'],
packages=find_packages(exclude=['tests']),
python_requires='~=3.4',
python_requires='>=3.4',
install_requires=[
'beautifulsoup4',
'demjson',
'lxml',
'demjson3',
'docopt',
'mutagen',
'requests',
@ -53,4 +58,8 @@ setup(
'bandcamp-dl=bandcamp_dl.__main__:main',
],
},
project_urls={
'Bug Reports': 'https://github.com/iheanyi/bandcamp-dl/issues',
'Source': 'https://github.com/iheanyi/bandcamp-dl',
},
)