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
  • master
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.11.0
  • v1.12.0
  • v1.12.1
  • v1.12.2
8 results

Target

Select target project
  • deadlocker8/SpotifyBackup
1 result
Select Git revision
  • master
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.11.0
  • v1.12.0
  • v1.12.1
  • v1.12.2
8 results
Show changes

Commits on Source 3

...@@ -3,6 +3,7 @@ import os.path ...@@ -3,6 +3,7 @@ import os.path
import time import time
from typing import List, Dict from typing import List, Dict
import click
import spotipy import spotipy
from TheCodeLabs_BaseUtils.DefaultLogger import DefaultLogger from TheCodeLabs_BaseUtils.DefaultLogger import DefaultLogger
from spotipy import SpotifyOAuth, CacheFileHandler from spotipy import SpotifyOAuth, CacheFileHandler
...@@ -60,7 +61,20 @@ class SpotifyRecorder: ...@@ -60,7 +61,20 @@ class SpotifyRecorder:
playlist = self.__get_playlist(self._playlist['user'], self._playlist['id']) playlist = self.__get_playlist(self._playlist['user'], self._playlist['id'])
tracks = self.__get_tracks(playlist) 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) self.__record_tracks(tracks)
else:
LOGGER.warning('Aborted')
def __get_playlist(self, username: str, playlistID: str) -> Dict: def __get_playlist(self, username: str, playlistID: str) -> Dict:
LOGGER.info(f'Fetching playlist with ID: {playlistID} by {username}...') LOGGER.info(f'Fetching playlist with ID: {playlistID} by {username}...')
...@@ -77,12 +91,9 @@ class SpotifyRecorder: ...@@ -77,12 +91,9 @@ class SpotifyRecorder:
tracks = self._spotify.next(tracks) tracks = self._spotify.next(tracks)
results.extend(tracks['items']) results.extend(tracks['items'])
LOGGER.info(f'Found {len(tracks)} tracks in playlist') LOGGER.info(f'Found {len(results)} tracks in playlist')
return results 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): def __record_tracks(self, tracks: list):
deviceId = self.__get_device_id_by_name(self._spotifyDeviceName) deviceId = self.__get_device_id_by_name(self._spotifyDeviceName)
...@@ -90,13 +101,6 @@ class SpotifyRecorder: ...@@ -90,13 +101,6 @@ class SpotifyRecorder:
skippedTrackNumbers = [] skippedTrackNumbers = []
errorTrackNumbers = [] 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): for index, track in enumerate(tracks):
indexInPlaylist = self._startNumber + index indexInPlaylist = self._startNumber + index
...@@ -110,12 +114,23 @@ class SpotifyRecorder: ...@@ -110,12 +114,23 @@ class SpotifyRecorder:
LOGGER.info(f'>>> Recording track {index + 1}/{len(tracks)}: ' LOGGER.info(f'>>> Recording track {index + 1}/{len(tracks)}: '
f'#{indexInPlaylist} "{track["track"]["name"]}"...') f'#{indexInPlaylist} "{track["track"]["name"]}"...')
try: 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) self.__stop_playback_if_playing(deviceId)
fileName = self.__determine_file_name(indexInPlaylist, track) fileName = self.__determine_file_name(indexInPlaylist, track)
filePathWav = f'{fileName}.wav' filePathWav = f'{fileName}.wav'
filePathMp3 = f'{fileName}.mp3' filePathMp3 = f'{fileName}.mp3'
recorder = AudioRecorder(self._audioDeviceName, filePathWav) recorder = AudioRecorder(self._audioDeviceName, filePathWav)
with recorder.record(): with recorder.record():
self.__play_track(deviceId, track['track']['uri']) self.__play_track(deviceId, track['track']['uri'])
timeWaitedForPlaying = self.__wait_for_track_playing(track['track']['id']) timeWaitedForPlaying = self.__wait_for_track_playing(track['track']['id'])
...@@ -130,18 +145,8 @@ class SpotifyRecorder: ...@@ -130,18 +145,8 @@ class SpotifyRecorder:
LOGGER.debug(f'\t\tRemoving wav file "{filePathWav}"') LOGGER.debug(f'\t\tRemoving wav file "{filePathWav}"')
os.remove(filePathWav) os.remove(filePathWav)
recordedTrackNumbers.append(indexInPlaylist) @staticmethod
except Exception as e: def __print_end_statistics(errorTrackNumbers: list[int], recordedTrackNumbers: list[int],
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],
skippedTrackNumbers: list[int], numberOfTracks: int): skippedTrackNumbers: list[int], numberOfTracks: int):
LOGGER.info('### DONE ###') LOGGER.info('### DONE ###')
...@@ -161,6 +166,11 @@ class SpotifyRecorder: ...@@ -161,6 +166,11 @@ class SpotifyRecorder:
fileName = f'{index} - {artists} - {track["track"]["name"]}' fileName = f'{index} - {artists} - {track["track"]["name"]}'
return os.path.join(self._destinationFolder, fileName) 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: def __wait_for_track_end(self, track, timeWaitedForPlaying: float) -> None:
trackDurationInMs = track['track']['duration_ms'] trackDurationInMs = track['track']['duration_ms']
trackDurationInSeconds = trackDurationInMs // 1000 trackDurationInSeconds = trackDurationInMs // 1000
......
...@@ -121,6 +121,31 @@ files = [ ...@@ -121,6 +121,31 @@ files = [
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, {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]] [[package]]
name = "idna" name = "idna"
version = "3.6" version = "3.6"
...@@ -352,4 +377,4 @@ zstd = ["zstandard (>=0.18.0)"] ...@@ -352,4 +377,4 @@ zstd = ["zstandard (>=0.18.0)"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "bb77de02b25207bf10249bf1370a69682b27ad88452311d42abc7d9830eb5494" content-hash = "91e52e9622d0f476c5b0352fb8295ee9c4cac6a50a35992cf142b11a7f4a7db9"
...@@ -15,6 +15,7 @@ thecodelabs-baseutils = {version = "*", source = "TheCodeLabs" } ...@@ -15,6 +15,7 @@ thecodelabs-baseutils = {version = "*", source = "TheCodeLabs" }
spotipy = "2.22.0" spotipy = "2.22.0"
PyAudioWPatch = "0.2.12.6" PyAudioWPatch = "0.2.12.6"
mutagen = "1.47.0" mutagen = "1.47.0"
click = "8.1.7"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
......