Skip to content

Instantly share code, notes, and snippets.

@yodaluca23
Last active July 19, 2024 06:23
Show Gist options
  • Select an option

  • Save yodaluca23/a9e8e9ef249c2b6d4dce2f3be0f23aa2 to your computer and use it in GitHub Desktop.

Select an option

Save yodaluca23/a9e8e9ef249c2b6d4dce2f3be0f23aa2 to your computer and use it in GitHub Desktop.

Revisions

  1. yodaluca23 renamed this gist Jul 19, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. yodaluca23 created this gist Jul 19, 2024.
    130 changes: 130 additions & 0 deletions SaveLyrics.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,130 @@
    # To get a MusixMatch token, download the app
    # Go to settings (Top right corner) > Scroll all the way down > click "Get help" > click "Copy debug info"
    # [UserToken] is your API key.
    # After this finishes, you can fill in the rest from libLRC database using https://github.com/tranxuanthang/lrcget

    import os
    import requests
    import json
    import re

    # Function to load configuration from config.txt
    def load_config():
    if os.path.exists('config.txt'):
    with open('config.txt', 'r') as config_file:
    config = json.load(config_file)
    return config.get('token'), config.get('naming_format')
    return None, None

    # Function to save configuration to config.txt
    def save_config(token, naming_format):
    with open('config.txt', 'w') as config_file:
    json.dump({'token': token, 'naming_format': naming_format}, config_file)

    # Load token and naming format from config.txt if it exists
    token, naming_format = load_config()

    if not token:
    token = input("Paste your MusixMatch token: ")
    if not naming_format:
    naming_format = input("Enter the naming format (use %A for artist and %T for title): ")

    # Save token and naming format to config.txt
    save_config(token, naming_format)

    # Ask the user if they want to override existing files
    override_existing = input("Do you want to override existing files? (yes/no): ").strip().lower() == 'yes'

    # List of supported file extensions
    supported_extensions = [
    ".3gp", ".aa", ".aac", ".aax", ".act", ".aiff", ".alac", ".amr", ".ape", ".au", ".awb", ".dss",
    ".dvf", ".flac", ".gsm", ".iklax", ".ivs", ".m4a", ".m4b", ".m4p", ".mmf", ".movpkg", ".mp3",
    ".mpc", ".msv", ".nmf", ".ogg", ".oga", ".mogg", ".opus", ".ra", ".rm", ".raw", ".rf64",
    ".sln", ".tta", ".voc", ".vox", ".wav", ".wma", ".wv", ".webm", ".8svx", ".cda"
    ]

    def extract_artist_and_song(filename, naming_format):
    # Add "." to properly extract ending thing
    naming_format = naming_format + "."
    # Define the placeholders and their corresponding regex patterns
    placeholders = {
    '%A': '(?P<artist>.+?)',
    '%T': '(?P<title>.+?)'
    }

    # Escape special regex characters in the naming format
    escaped_format = re.escape(naming_format)

    # Replace the placeholders in the escaped naming format with regex patterns
    for placeholder, pattern in placeholders.items():
    escaped_format = escaped_format.replace(re.escape(placeholder), pattern)

    # Create a regex pattern from the modified naming format
    pattern = re.compile(escaped_format)

    # Match the pattern with the filename
    match = pattern.match(filename)

    # If a match is found, extract the artist and title
    if match:
    artist = match.group('artist')
    title = match.group('title')
    return artist.strip(), title.strip()
    else:
    filename = filename.split('.')[0]
    print(f"The filename '{filename}' does not match the naming format '{naming_format}'")
    artist = "rhiugwbeguhwouehgouqhefoqnfobnqoefhouqehgoiuhqeoughqeouhgouq"
    title = "gfrwouehgowgoeqjhoghjewojgoirwdjgoiswrjdoifjqoiefjoqefgqrogjoiwrjgoesrjgjedo"
    return artist.strip(), title.strip()

    def fetch_and_save_lyrics(filename, artist, title, token, override_existing):
    lrc_filename = os.path.splitext(filename)[0] + '.lrc'
    if not override_existing and os.path.exists(lrc_filename):
    filename = filename.split('.')[0]
    print(f"Lyrics for {filename} already exist, skipping")
    return

    url = f'https://apic.musixmatch.com/ws/1.1/macro.subtitles.get?subtitle_format=lrc&q_track={title}&usertoken={token}&q_artist={artist}&app_id=mac-ios-v2.0'
    response = requests.get(url)
    data = response.json()

    try:
    lyrics_body = data['message']['body']['macro_calls']['track.subtitles.get']['message']['body']['subtitle_list'][0]['subtitle']['subtitle_body']
    if is_lyrics_blank(lyrics_body):
    raise ValueError("Time synced lyrics are blank or contain only whitespace.")
    save_lyrics(lrc_filename, lyrics_body, True, filename)
    except:
    filename = filename.split('.')[0]
    print(f"Could not find time synced lyrics for {filename}, trying non-time synced")
    try:
    lyrics_body = data['message']['body']['macro_calls']['track.lyrics.get']['message']['body']['lyrics']['lyrics_body']
    if is_lyrics_blank(lyrics_body):
    raise ValueError("Non-time synced lyrics are blank or contain only whitespace.")
    save_lyrics(lrc_filename, lyrics_body, False, filename)
    except:
    filename = filename.split('.')[0]
    print(f"Could not save lyrics for {filename}")

    def is_lyrics_blank(lyrics_body):
    return not lyrics_body.strip()

    def save_lyrics(lrc_filename, lyrics_body, is_time_synced, filename):
    lyrics_body = lyrics_body.replace("\\n", "\n")
    with open(lrc_filename, 'w') as lrc_file:
    lrc_file.write(lyrics_body)
    if is_time_synced:
    filename = filename.split('.')[0]
    print(f"Saved time-synced lyrics for {filename}")
    else:
    filename = filename.split('.')[0]
    print(f"Saved non-time-synced lyrics for {filename}")

    # Scan the current directory for supported audio files
    for item in os.listdir('.'):
    if any(item.endswith(ext) for ext in supported_extensions):
    artist, title = extract_artist_and_song(item, naming_format)
    if artist and title:
    fetch_and_save_lyrics(item, artist, title, token, override_existing)
    else:
    item = item.split('.')[0]
    print(f"Could not extract artist and title from {item}")