Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • deadlocker8/SpotifyBackup
1 result
Select Git revision
Loading items
Show changes
Commits on Source (3)
......@@ -3,6 +3,7 @@ import os.path
import time
from typing import List, Dict
import click
import spotipy
from TheCodeLabs_BaseUtils.DefaultLogger import DefaultLogger
from spotipy import SpotifyOAuth, CacheFileHandler
......@@ -60,7 +61,20 @@ class SpotifyRecorder:
playlist = self.__get_playlist(self._playlist['user'], self._playlist['id'])
tracks = self.__get_tracks(playlist)
if self._limit == -1:
LOGGER.info(f'Recording track #{self._startNumber} to end of playlist')
tracks = tracks[self._startNumber - 1:]
else:
LOGGER.info(f'Recording track #{self._startNumber} to (including) #{self._startNumber + self._limit - 1}')
tracks = tracks[self._startNumber - 1:self._startNumber - 1 + self._limit]
totalDurationInSeconds = sum([track['track']['duration_ms'] // 1000 for track in tracks])
LOGGER.info(f'Total duration: {self.__convert_seconds_to_duration(totalDurationInSeconds)}')
if click.confirm('Do you want to start recording?', default=True):
self.__record_tracks(tracks)
else:
LOGGER.warning('Aborted')
def __get_playlist(self, username: str, playlistID: str) -> Dict:
LOGGER.info(f'Fetching playlist with ID: {playlistID} by {username}...')
......@@ -77,12 +91,9 @@ class SpotifyRecorder:
tracks = self._spotify.next(tracks)
results.extend(tracks['items'])
LOGGER.info(f'Found {len(tracks)} tracks in playlist')
LOGGER.info(f'Found {len(results)} tracks in playlist')
return results
def __extract_track_uris(self, tracks: List) -> List[str]:
return [track['track']['uri'] for track in tracks]
def __record_tracks(self, tracks: list):
deviceId = self.__get_device_id_by_name(self._spotifyDeviceName)
......@@ -90,13 +101,6 @@ class SpotifyRecorder:
skippedTrackNumbers = []
errorTrackNumbers = []
if self._limit == -1:
LOGGER.info(f'Recording track #{self._startNumber} to all')
tracks = tracks[self._startNumber - 1:]
else:
LOGGER.info(f'Recording track #{self._startNumber} to (including) #{self._startNumber + self._limit - 1}')
tracks = tracks[self._startNumber - 1:self._startNumber - 1 + self._limit]
for index, track in enumerate(tracks):
indexInPlaylist = self._startNumber + index
......@@ -110,12 +114,23 @@ class SpotifyRecorder:
LOGGER.info(f'>>> Recording track {index + 1}/{len(tracks)}: '
f'#{indexInPlaylist} "{track["track"]["name"]}"...')
try:
self.__record_single_track(deviceId, indexInPlaylist, track)
recordedTrackNumbers.append(indexInPlaylist)
except Exception as e:
LOGGER.error(f'An error occurred while recording track "{track["track"]["name"]}"', exc_info=e)
errorTrackNumbers.append(indexInPlaylist)
self.__print_end_statistics(errorTrackNumbers, recordedTrackNumbers, skippedTrackNumbers, len(tracks))
def __record_single_track(self, deviceId, indexInPlaylist, track):
self.__stop_playback_if_playing(deviceId)
fileName = self.__determine_file_name(indexInPlaylist, track)
filePathWav = f'{fileName}.wav'
filePathMp3 = f'{fileName}.mp3'
recorder = AudioRecorder(self._audioDeviceName, filePathWav)
with recorder.record():
self.__play_track(deviceId, track['track']['uri'])
timeWaitedForPlaying = self.__wait_for_track_playing(track['track']['id'])
......@@ -130,18 +145,8 @@ class SpotifyRecorder:
LOGGER.debug(f'\t\tRemoving wav file "{filePathWav}"')
os.remove(filePathWav)
recordedTrackNumbers.append(indexInPlaylist)
except Exception as e:
LOGGER.error(f'An error occurred while recording track "{track["track"]["name"]}"', exc_info=e)
errorTrackNumbers.append(indexInPlaylist)
self.__print_end_statistics(errorTrackNumbers, recordedTrackNumbers, skippedTrackNumbers, len(tracks))
def __join_artists(self, track) -> str:
artists = track['track']['artists']
return ' & '.join(artist['name'] for artist in artists)
def __print_end_statistics(self, errorTrackNumbers: list[int], recordedTrackNumbers: list[int],
@staticmethod
def __print_end_statistics(errorTrackNumbers: list[int], recordedTrackNumbers: list[int],
skippedTrackNumbers: list[int], numberOfTracks: int):
LOGGER.info('### DONE ###')
......@@ -161,6 +166,11 @@ class SpotifyRecorder:
fileName = f'{index} - {artists} - {track["track"]["name"]}'
return os.path.join(self._destinationFolder, fileName)
@staticmethod
def __join_artists(track) -> str:
artists = track['track']['artists']
return ' & '.join(artist['name'] for artist in artists)
def __wait_for_track_end(self, track, timeWaitedForPlaying: float) -> None:
trackDurationInMs = track['track']['duration_ms']
trackDurationInSeconds = trackDurationInMs // 1000
......
......@@ -121,6 +121,31 @@ files = [
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
]
[[package]]
name = "click"
version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "idna"
version = "3.6"
......@@ -352,4 +377,4 @@ zstd = ["zstandard (>=0.18.0)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "bb77de02b25207bf10249bf1370a69682b27ad88452311d42abc7d9830eb5494"
content-hash = "91e52e9622d0f476c5b0352fb8295ee9c4cac6a50a35992cf142b11a7f4a7db9"
......@@ -15,6 +15,7 @@ thecodelabs-baseutils = {version = "*", source = "TheCodeLabs" }
spotipy = "2.22.0"
PyAudioWPatch = "0.2.12.6"
mutagen = "1.47.0"
click = "8.1.7"
[tool.poetry.dev-dependencies]
......