""" A set of common utilities. """ import json import re import pyaudacity def inputYN(text: str, default: bool=None): """ Prompty the user with a yes/no prompt. Args: text (str): The text displayed to the user. default (bool): The default answer. """ while True: i = input(text) if i.lower() in ['1', 'y', 'yes']: return True if i.lower() in ['0', 'n', 'no']: return False if default is not None and i == '': return default def parseLrcLine(lrcLine: str) -> [float, str]: """ Parses a line from an lrc file. Turns "[00:36.21] If you decide to stay" into [36.21, 'If you decide to stay']. Args: lrcLine (str): The single line from the lrc file. Returns: float: How many seconds into the song the lyric is. str: The lytic. """ t = None if re.search(r'^\[[0-9][0-9]:[0-9][0-9](\.[0-9][0-9])?\].*$', lrcLine): timeStamp = lrcLine[1:].split(']')[0] minutes, seconds = timeStamp.split(':') minutes, seconds = (int(minutes), float(seconds)) t = minutes * 60 + seconds lrcLine = ']'.join(lrcLine.split(']')[1:]).strip() return t, lrcLine def getInfo(getType: str) -> dict: """ Runs the `GetInfo` command and automatically parses the JSON. Args: getType (str): Passed into the `Type` argument of `GetInfo`. Returns: dict: The data Audacity returned. """ ret = pyaudacity.do(f'GetInfo: Format="JSON" Type="{getType}"') # Remove the surrounding bullshit then parse the JSON. return json.loads('\n'.join(ret.split('\n')[1:-2])) def getProjectLength() -> float: """ Returns how long the total project is. Returns: float: How long the project is in seconds. """ audioTracks = [track for track in getInfo('Tracks') if track['kind'] == 'wave'] if len(audioTracks) == 0: return 0 return max([track['end'] for track in audioTracks]) def getLRCTrackIndex(create: bool=False) -> int: """ Gets (or creates) an LRC label tracks index. Args: create (bool): If True, an LRC track will be created if none is found. Returns: int: The index of the LRC track or None if none was found. """ tracks = getInfo('Tracks') labelTracks = [t for t in tracks if t['kind'] == 'label'] validLRCTracks = [t for t in labelTracks if t['name'] == 'Lyrics'] if len(validLRCTracks) == 0: if not create: return None pyaudacity.do('NewLabelTrack') pyaudacity.do('TrackMoveTop') pyaudacity.do('SetTrackStatus: Name="Lyrics"') return 0 for idx, track in enumerate(tracks): if track['kind'] == 'label' and track['name'] == 'Lyrics': return idx def addLabel(trackIndex: int, time: float, text: str): """ Adds a label on track `trackIndex` at `time` with the text `text`. Args: trackIndex (int): The index of the label track. time (float): The time (in seconds) to add the label. text (str): The text to put in the label. """ # "sanitise" the text text = text.replace('"', '\\"') # ... what the fuck Audacity... pyaudacity.do('FirstTrack') for _ in range(trackIndex): pyaudacity.do('NextTrack') pyaudacity.do(f'SelectTime: Start="{time}" end="{time}"') pyaudacity.do('AddLabel') lastLabelIdx = sum([len(labels) for _, labels in getInfo('Labels')])-1 pyaudacity.do(f'SetLabel: Label="{lastLabelIdx}" Text="{text}"')