Forked from himenlinamarbric/spotifyHijack.scpt
Last active
December 19, 2019 15:57
-
-
Save hectormethod/6996a7dceee895aa9283 to your computer and use it in GitHub Desktop.
Audio Hijack Pro & Spotify -- No Polling #audio #mac #applescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Usage | |
-- 1. Edit the settings (see below). This step is NECESSARY the first time you use it! | |
-- 2. Run this script (this should open Audio Hijack Pro and Spotify) | |
-- | |
-- NOTE: the script assumes that each track is played entirely. You CANNOT skip tracks in Spotify. | |
-- If you do so the script will get out of sync and the resulting files contain partial or multiple songs. | |
-- You can abort a recordig session by stopping this script and ending (manually) the recording | |
-- in Audio Hijack Pro. | |
-- | |
-- You need to have "atomicparsley" installed on your system. You can install the application with | |
-- homebrew using "brew install atomicparsley" (see http://brew.sh/) | |
-- | |
-- The recording settings for Audio Hijack Pro NEED to be defined here, they CANNOT be changed | |
-- withing the application itself. | |
-- Every time the script is executed, the settings defined here are applied to Audio Hijack Pro, | |
-- customizations in the application are overwritten. | |
property output_folder : "/Users/USERNAME/Music/rec" | |
property atomicparsley_path : "/usr/local/bin/atomicparsley" | |
-- In order to change the output format, you need to find the line in this script which looks like | |
-- "set recording format of spotify_session to {...}" | |
-- If you change the output format, make sure to update the file_extension property to match the codec! | |
property file_extension : ".m4a" | |
on format_filename(track_artist, track_album, track_name, track_number) | |
set r to "" & track_artist & " - " & track_album & " - " & track_number & " - " & track_name & file_extension | |
set x to length of r | |
if (x > 250) then set x to 250 | |
return ((characters 1 thru x of r) as string) | |
end format_filename | |
tell application "Audio Hijack Pro" | |
activate | |
-- Find the "Spotify" session or create it if it doesn't exist. | |
try | |
set spotify_session to first session whose name is "Spotify" | |
on error number -1719 | |
tell application "Finder" | |
set spotify_path to POSIX path of (application file id "spty" as alias) | |
end tell | |
set spotify_session to make new application session at end of sessions | |
set name of spotify_session to "Spotify" | |
set targeted application of spotify_session to spotify_path | |
end try | |
-- Define / overwrite the settings of the "Spotify" session in Audio Hijack Pro. | |
-- This script only works correctly if the settings are as specified here. | |
set output folder of spotify_session to output_folder | |
set output name format of spotify_session to "%tag_title" | |
-- Audio format settings | |
set recording format of spotify_session to {encoding:AAC, bit rate:256, channels:Stereo} | |
-- set recording format of spotify_session to {encoding:MP3, bit rate:320, channels:Stereo, style:VBR} | |
-- (Re-)start hijacking and recording on the spotify session | |
if hijacked of spotify_session is true then | |
stop hijacking spotify_session | |
end if | |
start hijacking spotify_session relaunch yes | |
end tell | |
delay 2 | |
tell application "Spotify" | |
if not running then activate | |
if player state is playing then pause | |
if repeating then display dialog "Note that repeating is enabled in Spotify! You may want to disable it now." | |
end tell | |
tell application "Audio Hijack Pro" | |
display alert "Ready for recording. Please start playing the first song in the album / playlist, then click OK in this dialog." | |
end tell | |
tell application "Spotify" | |
set track_counter to 0 | |
set recorded_ids to {} | |
set track_id to my sp_next_track(recorded_ids, "") | |
set recorded_ids to recorded_ids & track_id | |
repeat until track_id is equal to "" | |
set track_counter to (track_counter + 1) | |
set metadata to my sp_current_metadata() | |
set track_length to (duration of current track) / 1000 | |
if my sp_is_ad(track_id) then | |
set sound volume to 0 | |
play | |
delay track_length | |
else | |
set player position to 0 | |
set sound volume to 100 | |
my ah_start_recording(spotify_session, track_counter) | |
play | |
delay track_length | |
my ah_stop_recording(spotify_session) | |
my save_metadata(metadata, track_counter) | |
end if | |
set track_id to my sp_next_track(recorded_ids, track_id) | |
if not my sp_is_ad(track_id) then | |
set recorded_ids to recorded_ids & track_id | |
end if | |
end repeat | |
end tell | |
on ah_start_recording(spotify_session, track_counter) | |
tell application "Audio Hijack Pro" | |
set title tag of spotify_session to track_counter | |
start recording spotify_session | |
end tell | |
end ah_start_recording | |
on ah_stop_recording(spotify_session) | |
tell application "Audio Hijack Pro" | |
stop recording spotify_session | |
end tell | |
end ah_stop_recording | |
on sp_is_ad(track_id) | |
return (track_id starts with "spotify:ad:") | |
end sp_is_ad | |
on sp_current_metadata() | |
tell application "Spotify" | |
try | |
set current_track to current track | |
set track_artist to artist of current_track | |
set track_album to album of current_track | |
set track_name to name of current_track | |
set track_number to track number of current_track | |
return {md_artist:track_artist, md_album:track_album, md_name:track_name, md_number:track_number} | |
on error number -1728 -- no current track | |
return {} | |
end try | |
end tell | |
end sp_current_metadata | |
on sp_next_track(recorded_ids, current_id) | |
tell application "Spotify" | |
try | |
set next_id to (id of current track) | |
on error number -1728 -- no current track | |
set next_id to current_id | |
end try | |
-- `next track` does not work on ads | |
repeat while next_id is equal to current_id | |
delay 1 | |
try | |
set next_id to (id of current track) | |
on error number -1728 -- no current track | |
set next_id to current_id | |
end try | |
end repeat | |
pause | |
if recorded_ids contains next_id then | |
return "" | |
else | |
return next_id | |
end if | |
end tell | |
end sp_next_track | |
on save_metadata(metadata, track_counter) | |
tell application "Spotify" | |
set track_artist to md_artist of metadata | |
set track_album to md_album of metadata | |
set track_name to md_name of metadata | |
set track_number to md_number of metadata | |
set new_filename to my format_filename(track_artist, track_album, track_name, track_number) | |
-- eliminate special characters from file name | |
-- TODO: keep brackets [], also other symbols | |
-- NOTE: 'do shell script' within a 'tell' block requires 'tell current application to', https://developer.apple.com/library/mac/releasenotes/AppleScript/RN-AppleScript/RN-10_6/RN-10_6.html#//apple_ref/doc/uid/TP40000982-CH106-SW6 | |
tell current application to set new_filename to do shell script ("echo \"" & new_filename & "\" | sed 's/[^a-zA-Z0-9 .äöüÄÖÜéèàç&(){}-]/_/g'") | |
my wait_file_exists(my temp_filename(track_counter, false)) | |
set current_file to my temp_filename(track_counter, true) | |
set new_file to ("\"" & output_folder & "/" & new_filename & "\"") | |
tell current application to do shell script ("mv " & current_file & " " & new_file) | |
-- update metadata (tags) | |
tell current application to do shell script atomicparsley_path & " " & new_file & " --artist \"" & track_artist & "\" --album \"" & track_album & "\" --title \"" & track_name & "\" --tracknum " & track_number & " --overWrite" | |
end tell | |
end save_metadata | |
on temp_filename(track_counter, add_quote) | |
set filename to output_folder & "/" & track_counter & file_extension | |
if add_quote then | |
return ("\"" & filename & "\"") | |
else | |
return filename | |
end if | |
end temp_filename | |
on wait_file_exists(filename) | |
set c to 0 | |
repeat until c is equal to 10 | |
if file_exists(filename) then | |
return | |
end if | |
set c to c + 1 | |
delay 0.1 | |
end repeat | |
error "output file could not be found: " & filename | |
end wait_file_exists | |
on file_exists(filename) | |
tell application "System Events" | |
if exists file filename then | |
return true | |
else | |
return false | |
end if | |
end tell | |
end file_exists |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much! This is working great