#!/usr/bin/env python3

import os
import re
import json
import requests
import threading

from concurrent.futures import ThreadPoolExecutor, as_completed
from syncedlyrics import search

SONGS_JSON = "songs.json"
LYRICS_DIR = "lyrics"

MAX_THREADS = 20
TIMEOUT = 15

os.makedirs(LYRICS_DIR, exist_ok=True)

lock = threading.Lock()

with open(SONGS_JSON, "r", encoding="utf8") as f:
    songs = json.load(f)


def clean_title(name):

    patterns = [
        r'\(lyrics?\)',
        r'\[lyrics?\]',
        r'official video.*',
        r'lyric video.*',
        r'tradução.*',
        r'legendado.*',
        r'slowed.*',
        r'reverb.*',
        r'phonk edition.*',
        r'\s+\|\s+.*',
    ]

    for p in patterns:
        name = re.sub(
            p,
            '',
            name,
            flags=re.I
        )

    return name.strip()


def save_lrc(song_name, lyrics):

    fname = (
        song_name
        .replace("/", "_")
        .replace("\\", "_")
    ) + ".lrc"

    path = os.path.join(
        LYRICS_DIR,
        fname
    )

    with lock:
        with open(
            path,
            "w",
            encoding="utf8"
        ) as f:
            f.write(lyrics)


def lrclib_search(query):

    try:

        r = requests.get(
            "https://lrclib.net/api/search",
            params={"q": query},
            timeout=TIMEOUT
        )

        if r.status_code != 200:
            return None

        data = r.json()

        if not data:
            return None

        for item in data:

            lyrics = (
                item.get("syncedLyrics")
                or item.get("plainLyrics")
            )

            if lyrics:
                return lyrics

    except:
        pass

    return None


def worker(song):

    song_name = song["name"]

    fname = (
        song_name
        .replace("/", "_")
        .replace("\\", "_")
    ) + ".lrc"

    path = os.path.join(
        LYRICS_DIR,
        fname
    )

    if os.path.exists(path):
        return f"SKIP {song_name}"

    query = clean_title(song_name)

    if song.get("artist") \
       and song["artist"] != "Unknown":

        query += " " + song["artist"]

    try:

        lyrics = search(
            query,
            enhanced=True
        )

        if lyrics:

            save_lrc(
                song_name,
                lyrics
            )

            return f"SYNC {song_name}"

    except:
        pass

    lyrics = lrclib_search(query)

    if lyrics:

        save_lrc(
            song_name,
            lyrics
        )

        return f"LRCLIB {song_name}"

    with lock:
        with open(
            "missing_lyrics.txt",
            "a",
            encoding="utf8"
        ) as f:
            f.write(song_name + "\n")

    return f"MISS {song_name}"


print(
    f"Loaded {len(songs)} songs"
)

with ThreadPoolExecutor(
    max_workers=MAX_THREADS
) as pool:

    futures = [
        pool.submit(worker, song)
        for song in songs
    ]

    for future in as_completed(futures):
        print(
            future.result()
        )

print("DONE")
