"""
downloads anime themes
"""
from pySmartDL import SmartDL
import time;start = time.time()
import os
import eyed3
import threading
import requests
import string
from animethemes import get_proper
from printer import fprint
from globals import Opts

FILENAME_BAD = set('#%&{}\\<>*?/$!\'":@+`|')
FILENAME_BANNED = set('<>:"/\\|?*')
FILENAME_ALLOWEDASCII = set(string.printable).difference(FILENAME_BANNED)

def generate_filename(
    anime_name_short,anime_name,
    song_name,theme_type,
    filetype='webm'
):
    """
    genererates a filename based off Opts.Download.filename
    """
    if Opts.Download.filename:
        filename = Opts.Download.filename
    else:
        filename =  f"%A %t (%S).%e"
    translate = {
        '%':'%',
        'a':anime_name_short,
        'A':anime_name,
        't':theme_type,
        's':song_name.replace(' ','_'),
        'S':song_name,
        'e':filetype
    }
    out = ''
    i = 0
    while i < len(filename):
        if filename[i] == '%':
            out += translate[filename[i+1]]
            i += 2
        else:
            out += filename[i]
            i += 1
    return out
    
    

def to_mal_priority(arg,no_raise=True):
    """
    converts an arg to mal priority
    0 = Low; 1 = Medium; 2 = High
    """
    if arg in {0,1,2}:
        return arg
    elif arg in '012':
        return int(arg)
    try:
        return {
            "low":0,
            "medium":1,
            "high":2
        }[arg.lower()]
    except KeyError:
        return arg

def remove_bad_nonascii(s):
    """
    removes all characters that shouldn't be in a filename and are not ascii
    """
    r = ''
    for i in s:
        if i in FILENAME_ALLOWEDASCII:
            r += i
    return r
            

def remove_bad_chars(s):
    """
    removes all characters that shouldn't be in a filename
    """
    if Opts.Download.ascii:
        return remove_bad_nonascii(s)
    
    r = ''
    for i in s:
        if i not in FILENAME_BANNED:
            r += i
    return r

def parse_download_data(anime_data):
    """
    parses anime data and converts it into download data
    [
        {
            filename,
            mirrors,
            audio_mirrors,
            metadata {...}
        }
    ]
    """
    fil_anititles = remove_bad_chars(anime_data["short_title"])
    fil_anititlel = remove_bad_chars(anime_data["title"])
    for theme in anime_data["themes"]:
        mirror = theme["mirrors"][0]
        url = mirror["mirror"]
        tags = mirror["quality"].split(', ')
        if (
            Opts.Download.sfw and 'NSFW' in theme['notes'] or
            Opts.Download.no_spoilers and 'Spoiler' in theme['notes'] or
            Opts.Download.no_dialogue and 'Trans' in tags
        ):
            continue
        mirrors = [i["mirror"] for i in theme["mirrors"]]
        audio_mirrors = [i["audio"] for i in theme["mirrors"]]
        fil_thetitle = remove_bad_chars(theme["title"])
        filename = generate_filename(
            fil_anititles,fil_anititlel,fil_thetitle,theme["type"])
        
        yield {
            "filename":filename,
            "mirrors":mirrors,
            "audio_mirrors":audio_mirrors,
            "metadata":{
                "title":theme["title"],
                "album":anime_data["title"],
                "year":anime_data["year"],
                "genre":145,
                "coverart":None
            }
        }

def get_download_data(username,statuses=[1,2],anilist=False,extra_ids=[],mal_args={}):
    """
    gets download data with a MAL/AniList username, adds extra anime and fiters out unwanted stuff
    """
    # [{"filename":"...","mirrors":[...],"metadata":{...}},...]
    out = []
    data = get_proper(username,anilist,extra_ids,**mal_args)
    fprint('parse','getting download data')
    for status in statuses:
        for anime in data[status]:
            if (anime['mal_data']['score'] < Opts.Animelist.minscore or
                to_mal_priority(anime['mal_data']['priority_string']) < Opts.Animelist.minpriority
            ):
                continue
            for theme,unparsed in zip(parse_download_data(anime),anime['themes']):
                
                theme["metadata"]["cover art"] = anime["cover"]
                out.append(theme)
    return out

def convert_ffmpeg(webm_filename,mp3_filename=None,save_folder=None):
    """
    convert a video file to an audio file with ffmpeg
    """
    if mp3_filename is None:
        mp3_filename = webm_filename[:-5]
    if save_folder is not None:
        mp3_filename = os.path.join(save_folder,os.path.basename(mp3_filename))
    mp3_filename += '.'+Opts.Download.audio_format
    loglevel = 'quiet' if Opts.Print.quiet else 'warning'
    ffmpeg_path = Opts.Download.ffmpeg
    os.system(f'{ffmpeg_path} -i "{webm_filename}" "{mp3_filename}" -y -stats -v quiet -loglevel {loglevel}')
    if not os.path.isfile(mp3_filename):
        fprint('error',"ffmpeg didn't convert, check if it's in path or use --ffmpeg")
        quit()
    return mp3_filename
    
def add_metadata(path,metadata,add_coverart):
    """
    adds metadata to an mp3 file
    returns True if succeeded, False if failed
    """
    if os.path.splitext(path)[1] != '.mp3':
        return False
    
    t = time.time()
    fprint(f'adding metadata for v2.4'+(' with coverart' if add_coverart else ''),end='')
    audiofile = eyed3.load(path)
    if (audiofile.tag == None):
        audiofile.initTag()
    
    audiofile.tag.album = metadata["album"]
    audiofile.tag.title = metadata["title"]
    audiofile.tag.year = metadata["year"]
    if add_coverart:
        image = requests.get(metadata["cover art"]).text.encode()
        audiofile.tag.images.set(3, image, 'image/jpeg')
    audiofile.tag.genre = 145
    
    try:
        audiofile.tag.save()
        fprint(' | '+str(int((time.time()-t)*1000))+'ms')
        return True
    except PermissionError as e:
        fprint('error',f"couldn't add metadata: {e}",start='\n')
        return False

def download_theme(theme_data,webm_folder=None,mp3_folder=None,no_redownload=False):
    """
    downloads a theme with given theme data and destination
    """
    # generate a folder to save webm files
    if webm_folder is None:
        filename = os.path.join(mp3_folder,theme_data["filename"])
    else:
        filename = os.path.join(webm_folder,theme_data["filename"])
    exwebm,exmp3 = os.path.isfile(filename),os.path.isfile(os.path.splitext(filename)[0]+'.mp3')
    
    # determine what files are needed
    if no_redownload:
        needmp3 = mp3_folder is not None and not exmp3
        needwebm = (webm_folder is not None and not exwebm) or (needmp3 and not exwebm)
    else:
        needwebm = True
        needmp3 = mp3_folder is not None
    
    # download webm file if file does not exist
    if needwebm:
        fprint('download',theme_data['filename'])
        obj = SmartDL(theme_data["mirrors"],filename,progress_bar=not Opts.Print.quiet)
        try:
            obj.start()
        except Exception as e:
            fprint('error',str(e))
        except KeyboardInterrupt:
            obj.stop()
            os.remove(obj.get_dest()+'.000')
            quit()
        webm_dest = obj.get_dest()
        remove_webm = True
    else:
        webm_dest = filename
        remove_webm = False
    
    # download mp3 file if file does not exist
    if needmp3:
        if not needwebm:
            fprint('convert',theme_data['filename'])
        mp3dest = convert_ffmpeg(webm_dest,save_folder=mp3_folder)
        add_metadata(mp3dest,theme_data["metadata"],Opts.Download.coverart)
    else:
        mp3dest = None
    
    # delete webm folder is deemed neccesary
    if webm_folder is None:
        if remove_webm:
            os.remove(webm_dest)
        webm_dest = None
    
    return {"mp3":mp3dest,"webm":webm_dest}

_LAST_DOWNLOAD_TIME = 10.0
def download_theme_audio_server(theme_data,mp3_folder=None,no_redownload=False,data_size=65536,timeout=10):
    """
    downloads an audio file from from a server
    the progress bar is completely fake
    
    returns:
    filename (str)
    empty str if no download was made
    None if all downloads failed
    """
    def progress_bar():
        """
        this progress bar is completely fake, but it makes it feel like something is happening so that's cool
        """
        global _LAST_DOWNLOAD_TIME
        START_TIME = time.time()
        last_increment = last_decrement = time.time()
        expected_remain = _LAST_DOWNLOAD_TIME+0.75
        current_time = lambda: time.time() - START_TIME
        def download_time(x,y,r=2):
            x = str(x).split('.')
            y = str(y).split('.')
            x = x[0]+'.'+x[1][:r]
            y = y[0]+'.'+y[1][:r]
            fprint("download",x+"s / "+y+"s", end="\r")
            return

        while True:
            download_time(current_time(),expected_remain)
            
            # time updater
            difference = expected_remain-current_time()
            if difference < 1:
                # never get it too close to the expected remain
                expected_remain += 1
                last_increment = time.time()
            elif time.time() - last_increment > 0.5 and difference < 10:
                # add time to make it look like it's updating
                expected_remain += 1/(expected_remain-current_time())
                last_increment = time.time()
            elif time.time() - last_decrement > 2:
                # remove some time because it feels good to make it faster
                expected_remain -= 2/(expected_remain-current_time())
                last_decrement = time.time()
                
            if STOP_PROGRESS_BAR:
                break
            if current_time() >= timeout:
                fprint('error','download timed out')
                return
        
        if FAKE_COMPLETE:
            fprint(download_string(current_time(),current_time()))
            _LAST_DOWNLOAD_TIME = current_time()
        else:
            fprint('')
        
        
    # generate a folder to save webm files
    short_filename = os.path.splitext(theme_data["filename"])[0]+'.mp3'
    filename = os.path.join(mp3_folder,short_filename)
    
    # download mp3 file if file does not exist
    if not (no_redownload and os.path.isfile(filename)):
        fprint('download',short_filename)
        for mirror in theme_data['audio_mirrors']:
            STOP_PROGRESS_BAR = False
            FAKE_COMPLETE = False
            thread = threading.Thread(target=progress_bar)
            thread.start()
            try:
                r = requests.get(mirror)
            except KeyboardInterrupt:
                STOP_PROGRESS_BAR = True
                thread.join()
                quit()
            except Exception as e:
                fprint('error',e)
                FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
                continue
                
            
            if r.status_code != 200:
                if r.status_code not in (500,404):
                    FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
                fprint('error',f'invalid mirror, got status code {r.status_code}')
                continue
            else:
                FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
            
            with open(filename, 'wb') as file:
                for data in r.iter_content(data_size): #64kiB
                    file.write(data)
            break
        else:
            fprint('error','all mirrors are invalid (press CTRL+C to stop program)')
            quit()
            return None
        
        add_metadata(filename,theme_data["metadata"],Opts.Download.coverart)
        return filename
    else:
        return ''


def download_multi_theme(download_data,webm_folder=None,mp3_folder=None):
    """
    downloads multiple themes with download data
    """
    if webm_folder is None and mp3_folder is None:
        fprint('error','no save folder set')
    if webm_folder and not os.path.isdir(webm_folder):
        os.mkdir(webm_folder)
    if mp3_folder and not os.path.isdir(mp3_folder):
        os.mkdir(mp3_folder)
    
    download_chooser = (lambda mthd: 
        download_theme(
            theme,webm_folder,mp3_folder,
            Opts.Download.no_redownload)
        if (mthd or webm_folder is not None) else
        download_theme_audio_server(
            theme,mp3_folder,
            Opts.Download.no_redownload)
    )
    
    # 0: external, 1: local
    if Opts.Download.local_convert or webm_folder is not None:
        mthd = 1
        fprint('progress','started downloading'+(' and converting' if mp3_folder is not None else ''))
    else:
        mthd = 0
        fprint('progress','started downloading audio files')
    
    
    for theme in download_data:
        filename = None
        while filename is None:
            filename = download_chooser(mthd)
            if filename is None and Opts.Download.try_both:
                filename = download_chooser(not mthd)
                
            if not Opts.Download.retry_forever:
                break

def batch_download(
    username,
    statuses=[1,2],
    webm_folder=None,mp3_folder=None,
    anilist=False,
    extra_ids=[]
):
    """
    basically the main function
    given a username and destination, downloads all themes from MAL/AniList
    """
    fprint('progress','initializing program')
    download_data = get_download_data(username,statuses,anilist,extra_ids)
    download_multi_theme(download_data,webm_folder,mp3_folder)
    fprint('progress','finished downloading')


if __name__ == "__main__":
    pass
    

"""
downloads anime themes
"""
from pySmartDL import SmartDL
import time;start = time.time()
import os
import eyed3
import threading
import requests
import string
from animethemes import get_proper
from printer import fprint
from globals import Opts

FILENAME_BAD = set('#%&{}\\<>*?/$!\'":@+`|')
FILENAME_BANNED = set('<>:"/\\|?*')
FILENAME_ALLOWEDASCII = set(string.printable).difference(FILENAME_BANNED)

def generate_filename(
    anime_name_short,anime_name,
    song_name,theme_type,
    filetype='webm'
):
    """
    genererates a filename based off Opts.Download.filename
    """
    if Opts.Download.filename:
        filename = Opts.Download.filename
    else:
        filename =  f"%A %t (%S).%e"
    translate = {
        '%':'%',
        'a':anime_name_short,
        'A':anime_name,
        't':theme_type,
        's':song_name.replace(' ','_'),
        'S':song_name,
        'e':filetype
    }
    out = ''
    i = 0
    while i < len(filename):
        if filename[i] == '%':
            out += translate[filename[i+1]]
            i += 2
        else:
            out += filename[i]
            i += 1
    return out
    
    

def to_mal_priority(arg,no_raise=True):
    """
    converts an arg to mal priority
    0 = Low; 1 = Medium; 2 = High
    """
    if arg in {0,1,2}:
        return arg
    elif arg in '012':
        return int(arg)
    try:
        return {
            "low":0,
            "medium":1,
            "high":2
        }[arg.lower()]
    except KeyError:
        return arg

def remove_bad_nonascii(s):
    """
    removes all characters that shouldn't be in a filename and are not ascii
    """
    r = ''
    for i in s:
        if i in FILENAME_ALLOWEDASCII:
            r += i
    return r
            

def remove_bad_chars(s):
    """
    removes all characters that shouldn't be in a filename
    """
    if Opts.Download.ascii:
        return remove_bad_nonascii(s)
    
    r = ''
    for i in s:
        if i not in FILENAME_BANNED:
            r += i
    return r

def parse_download_data(anime_data):
    """
    parses anime data and converts it into download data
    [
        {
            filename,
            mirrors,
            audio_mirrors,
            metadata {...}
        }
    ]
    """
    fil_anititles = remove_bad_chars(anime_data["short_title"])
    fil_anititlel = remove_bad_chars(anime_data["title"])
    for theme in anime_data["themes"]:
        mirror = theme["mirrors"][0]
        url = mirror["mirror"]
        tags = mirror["quality"].split(', ')
        if (
            Opts.Download.sfw and 'NSFW' in theme['notes'] or
            Opts.Download.no_spoilers and 'Spoiler' in theme['notes'] or
            Opts.Download.no_dialogue and 'Trans' in tags
        ):
            continue
        mirrors = [i["mirror"] for i in theme["mirrors"]]
        audio_mirrors = [i["audio"] for i in theme["mirrors"]]
        fil_thetitle = remove_bad_chars(theme["title"])
        filename = generate_filename(
            fil_anititles,fil_anititlel,fil_thetitle,theme["type"])
        
        yield {
            "filename":filename,
            "mirrors":mirrors,
            "audio_mirrors":audio_mirrors,
            "metadata":{
                "title":theme["title"],
                "album":anime_data["title"],
                "year":anime_data["year"],
                "genre":145,
                "coverart":None
            }
        }

def get_download_data(username,statuses=[1,2],anilist=False,extra_ids=[],mal_args={}):
    """
    gets download data with a MAL/AniList username, adds extra anime and fiters out unwanted stuff
    """
    # [{"filename":"...","mirrors":[...],"metadata":{...}},...]
    out = []
    data = get_proper(username,anilist,extra_ids,**mal_args)
    fprint('parse','getting download data')
    for status in statuses:
        for anime in data[status]:
            if (anime['mal_data']['score'] < Opts.Animelist.minscore or
                to_mal_priority(anime['mal_data']['priority_string']) < Opts.Animelist.minpriority
            ):
                continue
            for theme,unparsed in zip(parse_download_data(anime),anime['themes']):
                
                theme["metadata"]["cover art"] = anime["cover"]
                out.append(theme)
    return out

def convert_ffmpeg(webm_filename,mp3_filename=None,save_folder=None):
    """
    convert a video file to an audio file with ffmpeg
    """
    if mp3_filename is None:
        mp3_filename = webm_filename[:-5]
    if save_folder is not None:
        mp3_filename = os.path.join(save_folder,os.path.basename(mp3_filename))
    mp3_filename += '.'+Opts.Download.audio_format
    loglevel = 'quiet' if Opts.Print.quiet else 'warning'
    ffmpeg_path = Opts.Download.ffmpeg
    os.system(f'{ffmpeg_path} -i "{webm_filename}" "{mp3_filename}" -y -stats -v quiet -loglevel {loglevel}')
    if not os.path.isfile(mp3_filename):
        fprint('error',"ffmpeg didn't convert, check if it's in path or use --ffmpeg")
        quit()
    return mp3_filename
    
def add_metadata(path,metadata,add_coverart):
    """
    adds metadata to an mp3 file
    returns True if succeeded, False if failed
    """
    if os.path.splitext(path)[1] != '.mp3':
        return False
    
    t = time.time()
    fprint(f'adding metadata for v2.4'+(' with coverart' if add_coverart else ''),end='')
    audiofile = eyed3.load(path)
    if (audiofile.tag == None):
        audiofile.initTag()
    
    audiofile.tag.album = metadata["album"]
    audiofile.tag.title = metadata["title"]
    audiofile.tag.year = metadata["year"]
    if add_coverart:
        image = requests.get(metadata["cover art"]).text.encode()
        audiofile.tag.images.set(3, image, 'image/jpeg')
    audiofile.tag.genre = 145
    
    try:
        audiofile.tag.save()
        fprint(' | '+str(int((time.time()-t)*1000))+'ms')
        return True
    except PermissionError as e:
        fprint('error',f"couldn't add metadata: {e}",start='\n')
        return False

def download_theme(theme_data,webm_folder=None,mp3_folder=None,no_redownload=False):
    """
    downloads a theme with given theme data and destination
    """
    # generate a folder to save webm files
    if webm_folder is None:
        filename = os.path.join(mp3_folder,theme_data["filename"])
    else:
        filename = os.path.join(webm_folder,theme_data["filename"])
    exwebm,exmp3 = os.path.isfile(filename),os.path.isfile(os.path.splitext(filename)[0]+'.mp3')
    
    # determine what files are needed
    if no_redownload:
        needmp3 = mp3_folder is not None and not exmp3
        needwebm = (webm_folder is not None and not exwebm) or (needmp3 and not exwebm)
    else:
        needwebm = True
        needmp3 = mp3_folder is not None
    
    # download webm file if file does not exist
    if needwebm:
        fprint('download',theme_data['filename'])
        obj = SmartDL(theme_data["mirrors"],filename,progress_bar=not Opts.Print.quiet)
        try:
            obj.start()
        except Exception as e:
            fprint('error',str(e))
        except KeyboardInterrupt:
            obj.stop()
            os.remove(obj.get_dest()+'.000')
            quit()
        webm_dest = obj.get_dest()
        remove_webm = True
    else:
        webm_dest = filename
        remove_webm = False
    
    # download mp3 file if file does not exist
    if needmp3:
        if not needwebm:
            fprint('convert',theme_data['filename'])
        mp3dest = convert_ffmpeg(webm_dest,save_folder=mp3_folder)
        add_metadata(mp3dest,theme_data["metadata"],Opts.Download.coverart)
    else:
        mp3dest = None
    
    # delete webm folder is deemed neccesary
    if webm_folder is None:
        if remove_webm:
            os.remove(webm_dest)
        webm_dest = None
    
    return {"mp3":mp3dest,"webm":webm_dest}

_LAST_DOWNLOAD_TIME = 10.0
def download_theme_audio_server(theme_data,mp3_folder=None,no_redownload=False,data_size=65536,timeout=10):
    """
    downloads an audio file from from a server
    the progress bar is completely fake
    
    returns:
    filename (str)
    empty str if no download was made
    None if all downloads failed
    """
    def progress_bar():
        """
        this progress bar is completely fake, but it makes it feel like something is happening so that's cool
        """
        global _LAST_DOWNLOAD_TIME
        START_TIME = time.time()
        last_increment = last_decrement = time.time()
        expected_remain = _LAST_DOWNLOAD_TIME+0.75
        current_time = lambda: time.time() - START_TIME
        def download_time(x,y,r=2):
            x = str(x).split('.')
            y = str(y).split('.')
            x = x[0]+'.'+x[1][:r]
            y = y[0]+'.'+y[1][:r]
            fprint("download",x+"s / "+y+"s", end="\r")
            return

        while True:
            download_time(current_time(),expected_remain)
            
            # time updater
            difference = expected_remain-current_time()
            if difference < 1:
                # never get it too close to the expected remain
                expected_remain += 1
                last_increment = time.time()
            elif time.time() - last_increment > 0.5 and difference < 10:
                # add time to make it look like it's updating
                expected_remain += 1/(expected_remain-current_time())
                last_increment = time.time()
            elif time.time() - last_decrement > 2:
                # remove some time because it feels good to make it faster
                expected_remain -= 2/(expected_remain-current_time())
                last_decrement = time.time()
                
            if STOP_PROGRESS_BAR:
                break
            if current_time() >= timeout:
                fprint('error','download timed out')
                return
        
        if FAKE_COMPLETE:
            fprint(download_string(current_time(),current_time()))
            _LAST_DOWNLOAD_TIME = current_time()
        else:
            fprint('')
        
        
    # generate a folder to save webm files
    short_filename = os.path.splitext(theme_data["filename"])[0]+'.mp3'
    filename = os.path.join(mp3_folder,short_filename)
    
    # download mp3 file if file does not exist
    if not (no_redownload and os.path.isfile(filename)):
        fprint('download',short_filename)
        for mirror in theme_data['audio_mirrors']:
            STOP_PROGRESS_BAR = False
            FAKE_COMPLETE = False
            thread = threading.Thread(target=progress_bar)
            thread.start()
            try:
                r = requests.get(mirror)
            except KeyboardInterrupt:
                STOP_PROGRESS_BAR = True
                thread.join()
                quit()
            except Exception as e:
                fprint('error',e)
                FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
                continue
                
            
            if r.status_code != 200:
                if r.status_code not in (500,404):
                    FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
                fprint('error',f'invalid mirror, got status code {r.status_code}')
                continue
            else:
                FAKE_COMPLETE = True
                STOP_PROGRESS_BAR = True
                thread.join()
            
            with open(filename, 'wb') as file:
                for data in r.iter_content(data_size): #64kiB
                    file.write(data)
            break
        else:
            fprint('error','all mirrors are invalid (press CTRL+C to stop program)')
            quit()
            return None
        
        add_metadata(filename,theme_data["metadata"],Opts.Download.coverart)
        return filename
    else:
        return ''


def download_multi_theme(download_data,webm_folder=None,mp3_folder=None):
    """
    downloads multiple themes with download data
    """
    if webm_folder is None and mp3_folder is None:
        fprint('error','no save folder set')
    if webm_folder and not os.path.isdir(webm_folder):
        os.mkdir(webm_folder)
    if mp3_folder and not os.path.isdir(mp3_folder):
        os.mkdir(mp3_folder)
    
    download_chooser = (lambda mthd: 
        download_theme(
            theme,webm_folder,mp3_folder,
            Opts.Download.no_redownload)
        if (mthd or webm_folder is not None) else
        download_theme_audio_server(
            theme,mp3_folder,
            Opts.Download.no_redownload)
    )
    
    # 0: external, 1: local
    if Opts.Download.local_convert or webm_folder is not None:
        mthd = 1
        fprint('progress','started downloading'+(' and converting' if mp3_folder is not None else ''))
    else:
        mthd = 0
        fprint('progress','started downloading audio files')
    
    
    for theme in download_data:
        filename = None
        while filename is None:
            filename = download_chooser(mthd)
            if filename is None and Opts.Download.try_both:
                filename = download_chooser(not mthd)
                
            if not Opts.Download.retry_forever:
                break

def batch_download(
    username,
    statuses=[1,2],
    webm_folder=None,mp3_folder=None,
    anilist=False,
    extra_ids=[]
):
    """
    basically the main function
    given a username and destination, downloads all themes from MAL/AniList
    """
    fprint('progress','initializing program')
    download_data = get_download_data(username,statuses,anilist,extra_ids)
    download_multi_theme(download_data,webm_folder,mp3_folder)
    fprint('progress','finished downloading')


if __name__ == "__main__":
    pass
    

downloads anime themes genererates a filename based off Opts.Download.filename converts an arg to mal priority     0 = Low; 1 = Medium; 2 = High removes all characters that shouldn't be in a filename and are not ascii removes all characters that shouldn't be in a filename parses anime data and converts it into download data     [         {             filename,             mirrors,             audio_mirrors,             metadata {...}         }     ] gets download data with a MAL/AniList username, adds extra anime and fiters out unwanted stuff # [{"filename":"...","mirrors":[...],"metadata":{...}},...] convert a video file to an audio file with ffmpeg adds metadata to an mp3 file     returns True if succeeded, False if failed downloads a theme with given theme data and destination # generate a folder to save webm files # determine what files are needed # download webm file if file does not exist # download mp3 file if file does not exist # delete webm folder is deemed neccesary downloads an audio file from from a server     the progress bar is completely fake          returns:     filename (str)     empty str if no download was made     None if all downloads failed this progress bar is completely fake, but it makes it feel like something is happening so that's cool # time updater # never get it too close to the expected remain # add time to make it look like it's updating # remove some time because it feels good to make it faster # generate a folder to save webm files # download mp3 file if file does not exist #64kiB downloads multiple themes with download data # 0: external, 1: local basically the main function     given a username and destination, downloads all themes from MAL/AniList