diff --git a/spotigrab.py b/spotigrab.py
index 12b7ab1..8a5f0c7 100644
--- a/spotigrab.py
+++ b/spotigrab.py
@@ -9,19 +9,48 @@ import logging
import string
import unicodedata
import sys
+import os
# configuration
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)-8s %(message)s'
)
-rec_path=".\\rec\\"
-loopback_dev="3"
-monitor_interval=.2
+
+rec_path = os.path.join('.', 'rec')
+fmedia_path = os.path.join('fmedia', 'fmedia.exe')
+window_monitor_interval = .2
+
+window_regex = '^Spotify .+'
+metadata_regex = '^Spotify - (?P
.+) · (?P.+)'
+
# end configuration
valid_filename_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
-counter=0
+counter = 0
+is_recording = False
+
+
+def get_default_device():
+ device_list = subprocess.run([
+ fmedia_path,
+ '--list-dev'
+ ],
+ capture_output=True
+ )
+
+ playback_devices = device_list.stdout.decode('utf-8')
+ playback_devices = playback_devices.split('Loopback:')[1].split('Capture:')[0]
+ playback_devices = playback_devices.split('\n')
+
+ for device in playback_devices:
+ if re.search('- Default$', device):
+ logging.debug('found default output device: {device}'.format(device=device))
+ device_number = re.match('^device #([0-9]+)', device).group(1)
+ break
+
+ return device_number
+
def clean_filename(filename, whitelist=valid_filename_chars):
# keep only valid ascii chars
@@ -31,35 +60,45 @@ def clean_filename(filename, whitelist=valid_filename_chars):
cleaned_filename = ''.join(c for c in cleaned_filename if c in whitelist)
return cleaned_filename
-def start_rec(artist, title):
+
+def start_rec(artist: str, title: str):
def rec_subprocess():
- filename = '{rec_path}{nn:03d}. {artist} - {title}.mp3'.format(
- nn=counter,
- rec_path=rec_path,
- artist=clean_filename(artist),
- title=clean_filename(title)
- )
- logging.debug('recording to {filename}'.format(filename=filename))
- command = 'fmedia --record --dev-loopback={device} -o "{filename}" --mpeg-quality=2 --globcmd=listen'.format(device=loopback_dev, filename=filename)
- logging.debug('starting recording subprocess: {command}'.format(command=command))
- subprocess.run(command, shell=True, capture_output=True, check=True)
+ filename = os.path.join(
+ rec_path,
+ f'{counter:03d}. {clean_filename(artist)} - {clean_filename(title)}.mp3'
+ )
+ logging.debug(f'recording to {filename}')
+
+ command = [
+ fmedia_path,
+ '--record',
+ f'--dev-loopback={loopback_dev}',
+ f'--out={filename}',
+ '--mpeg-quality=2',
+ f'--meta=artist={artist};title={title};tracknumber={counter}',
+ '--globcmd=listen'
+ ]
+
+ logging.debug(f'starting recording subprocess: {" ".join(command)}')
+
+ subprocess.run(command, check=True, capture_output=True)
+
+ global counter
+ global is_recording
+ counter += 1
+ is_recording = True
logging.debug('starting subprocess')
- global counter
- counter += 1
thread = threading.Thread(target=rec_subprocess)
thread.start()
+
def stop_rec():
- subprocess.run('fmedia --globcmd=stop', shell=True)
+ subprocess.run([fmedia_path, '--globcmd=stop'])
+ global is_recording
+ is_recording = False
logging.debug('stopped recording')
-def parse_win_title(win_title):
- metadata = win_title.split('Spotify - ')[1].split(' · ')
- title = metadata[0]
- artist = metadata[1]
- logging.debug('got metadata {title} by {artist}'.format(title=title, artist=artist))
- return title, artist
def watch_window():
old_title = ''
@@ -68,28 +107,45 @@ def watch_window():
while True:
win_titles = pygetwindow.getAllTitles()
for win_title in win_titles:
- if re.search('^Spotify - .+', win_title):
+ if re.search(window_regex, win_title):
if win_title != old_title:
- logging.debug('window title changed to {wintitle}'.format(wintitle=win_title))
+ logging.debug(f'window title changed to {win_title}')
- # read metadata from window title
- title, artist = parse_win_title(win_title)
-
- if old_title != '':
- logging.debug('stop recording')
+ if is_recording:
stop_rec()
-
- logging.debug('start recording now')
- start_rec(title, artist)
-
- old_title = win_title
- time.sleep(.5)
-input('press enter to arm')
+ # if changed title matches the metadata regex it is assumed there is a song playing
+ if re.match(metadata_regex, win_title):
+ # read metadata from window title
+ metadata = re.match(metadata_regex, win_title)
+ title = metadata.group('title')
+ artist = metadata.group('artist')
+ logging.debug(f'got metadata ({title}) by ({artist})')
+
+ logging.debug('start recording now')
+ start_rec(title=title, artist=artist)
+
+ old_title = win_title
+
+ time.sleep(window_monitor_interval)
+
+
try:
+ loopback_dev = get_default_device()
+
+ number_input = input('enter number to start counting filenames from (or press enter for 1): ')
+
+ if number_input != '':
+ try:
+ counter = int(number_input) - 1
+ except ValueError:
+ logging.warning(f'input "{number_input}" is a invalid number input')
+
watch_window()
+
except KeyboardInterrupt:
logging.info('got CTRL+C - trying to clean up my mess')
- stop_rec()
+ if is_recording:
+ stop_rec()
logging.info('Bye Bye')
sys.exit(0)