Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions spotrec.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
_underscored_filenames = False
_use_internal_track_counter = False
_add_cover_art = False
_continuous_recording = False

# Hard-coded settings
_pa_recording_sink_name = "spotrec"
Expand All @@ -59,6 +60,8 @@
# Variables that change during runtime
is_script_paused = False
is_first_playing = True
is_recording = False
is_downloading = False
pa_spotify_sink_input_id = -1
internal_track_counter = 1
is_shutting_down = False
Expand Down Expand Up @@ -115,6 +118,15 @@ def doExit():
# Unload PulseAudio sink
PulseAudio.unload_sink()

# Wait 5 max 5 seconds for cover art download
global _add_cover_art
if _add_cover_art:
log.info(f"[{app_name}] Waiting for cover art download")
global is_downloading
while time.time() < time.time() + 5:
if not is_downloading: break
time.sleep(0.25)

log.info(f"[{app_name}] Bye")

# Have to use os exit here, because otherwise GLib would print a strange error message
Expand All @@ -131,6 +143,7 @@ def handle_command_line():
global _underscored_filenames
global _use_internal_track_counter
global _add_cover_art
global _continuous_recording

parser = argparse.ArgumentParser(
description=app_name + " v" + app_version, formatter_class=argparse.RawTextHelpFormatter)
Expand All @@ -153,6 +166,8 @@ def handle_command_line():
action="store_true", default=_use_internal_track_counter)
parser.add_argument("-a", "--add-cover-art", help="Embed the cover art from Spotify into the file",
action="store_true", default=_add_cover_art)
parser.add_argument("-C", "--continuous-recording", help="Do not split tracks into single file, record altogether (including ads - use premium)",
action="store_true", default=_continuous_recording)

args = parser.parse_args()

Expand All @@ -172,6 +187,7 @@ def handle_command_line():

_add_cover_art = args.add_cover_art

_continuous_recording = args.continuous_recording

def init_log():
global log
Expand Down Expand Up @@ -296,14 +312,17 @@ def __init__(self, parent, *args):

def run(self):
global is_script_paused
global is_recording
global _output_directory
global _continuous_recording

# Save current trackid to check later if it is still the same song playing (to avoid a bug when user skipped a song)
self.trackid_when_thread_started = self.parent.trackid

# Stop the recording before
# Use copy() to not change the list during this method runs
self.parent.stop_old_recording(FFmpeg.instances.copy())
if not _continuous_recording:
self.parent.stop_old_recording(FFmpeg.instances.copy())

# This is currently the only way to seek to the beginning (let it Play for some seconds, Pause and send Previous)
time.sleep(_playback_time_before_seeking_to_beginning)
Expand All @@ -319,15 +338,24 @@ def run(self):

# Exit after playlist recorded
if not is_script_paused:
# Stop the recording, self.parent.stop_old_recording(FFmpeg.instances.copy()) did not work?
log.debug(f"[{app_name}] Clean FFmpeg.killAll before regular exit")
if _continuous_recording:
FFmpeg.killAll()
doExit()

return

# Do not record ads
if self.parent.trackid.startswith("spotify:ad:"):
log.debug(f"[{app_name}] Skipping ad")
return


# Continue recording, not stopped
if is_recording:
log.info(f"[{app_name}] Continuous recording is enabled, still recording")
return

log.info(f"[{app_name}] Starting recording")

# Set is_script_paused to not trigger wrong Pause event in playbackstatus_changed()
Expand All @@ -349,7 +377,9 @@ def run(self):
# Start FFmpeg recording
ff = FFmpeg()
ff.record(self.out_dir,
self.parent.track, self.parent.get_metadata_for_ffmpeg())
self.parent.track, self.parent.get_metadata_for_ffmpeg())
# Add recording bool for continuous recording
is_recording = True

# Give FFmpeg some time to start up before starting the song
time.sleep(_recording_time_before_song)
Expand Down Expand Up @@ -487,6 +517,7 @@ def record(self, out_dir: str, file: str, metadata_for_file={}):

# The blocking version of this method waits until the process is dead
def stop_blocking(self):
global is_recording
# Remove from instances list (and terminate)
if self in self.instances:
self.instances.remove(self)
Expand Down Expand Up @@ -537,6 +568,7 @@ def run(self):

# Remove process from memory (and don't left a ffmpeg 'zombie' process)
self.process = None
is_recording = False

# Kill the process in the background
def stop(self):
Expand All @@ -554,6 +586,9 @@ def run(self):
# add cover art to temp _withArtwork file
# and then move it to replace the original file
def add_cover_art(self, fullfilepath):
# This is to keep running until art works are downloaded in continuous recording mode
global is_downloading
is_downloading = True
if self.cover_url is None:
log.debug(f'[FFmpeg] No cover art found for {fullfilepath}')
return
Expand Down Expand Up @@ -592,12 +627,14 @@ def add_cover_art(self, fullfilepath):
shlex.quote(temp_file)).returncode
if returncode != 0:
log.warning(f"[FFmpeg] Failed adding artwork to {fullfilepath}")
is_downloading = False
return
# overwrite the actual file by the temp file
log.debug(
f'[FFmpeg] Added cover art for {fullfilepath} in temp file, moving it')
shutil.move(temp_file, fullfilepath)
os.remove(cover_file) # now delete the cover art
is_downloading = False

@staticmethod
def killAll():
Expand Down