Beispiel #1
0
def _get_next_song(chat_id):
    """
    Get lyrics for the next song in the album.
    """
    msg = 'OOPS'
    try:
        last_res = DB.get_last_res(chat_id)
        if not last_res:
            return "You haven't searched for anything yet"

        album = last_res['album']
        album = album if album != 'Unknown' else None
        song = Song(last_res['artist'], last_res['title'], album)
        tracks = get_album_tracks(song)
        if not tracks:
            logger.info('no track list found')
            return 'Could not find the album this song belongs to'

        title = song.title.lower()
        if title not in tracks:
            logger.info('title not found in track list')
            return 'Could not find the album this song belongs to'
        if title == tracks[-1]:
            return 'That was the last song on the album'
        new_title = tracks[tracks.index(title) + 1]
        new_song = Song(artist=song.artist, title=new_title, album=song.album)
        msg = get_lyrics(new_song, chat_id)
    except sqlite3.Error:
        msg = ("There was an error while looking through the conversation's "
               "history. This command is unavailable for now.")
    return msg
Beispiel #2
0
def test_argv_by_name(monkeypatch):
    """
    Check that the program accepts a song or list of songs by name, and
    returns a list of song objects with the information it parsed.
    """
    # Run it first with only one song
    artist, title = 'judas priest', 'no surrender'
    new_args = [__file__, f'{artist} - {title}']
    param_song = Song(artist, title)
    monkeypatch.setattr(sys, 'argv', new_args)
    songs = parse_argv()
    assert songs == set([param_song])

    # Then try with multiple songs
    param_songs = [
        Song('kreator', 'mars mantra'),
        Song('nervosa', 'morbid courage'),
        Song('ac/dc', 'night prowler'),
    ]
    new_args = [__file__]
    for p_song in param_songs:
        new_args.append(f'{p_song.artist} - {p_song.title}')
    monkeypatch.setattr(sys, 'argv', new_args)
    songs = parse_argv()
    assert songs == set(param_songs)
Beispiel #3
0
def test_song_from_string_errors():
    """
    Test the different errors that may be raised from calling
    Song.from_string().
    """
    assert Song.from_string('in flames versus terminus') is None
    assert Song.from_string('The sword -') is None
    assert Song.from_string('- Letterbomb') is None
Beispiel #4
0
def test_song_from_filename_errors():
    """
    Test the different errors that may be raised from calling
    Song.from_filename().
    """
    assert Song.from_filename('') is None

    with NamedTemporaryFile() as temp:
        assert Song.from_filename(temp.name) is None

    with TemporaryDirectory() as temp:
        assert Song.from_filename(temp) is None
Beispiel #5
0
def test_now(bot, monkeypatch, bot_arg, update):
    """
    Test the 'now' function.
    """
    print('all', bot.DB._execute('select * from sp_tokens'))
    chat_id = update.message.chat_id
    token = 'token'

    def save_token():
        time.sleep(1)
        database = Database()
        database.config(bot.DB._filename)
        database.save_sp_token(token, chat_id)

    access_token = {
        'access_token': token + '2',
        'expires_at': (time.time() + 100),
        'refresh_token': token + '_refresh',
    }
    monkeypatch.setattr(bot.SP, 'get_access_token', lambda x: access_token)

    Thread(target=save_token).start()
    monkeypatch.setattr(bot.SP, 'currently_playing', lambda x: None)
    bot.now(bot_arg, update)
    assert bot_arg.msg_log[0] == 'Please open this link to log in to Spotify'
    assert bot_arg.msg_log[1] == bot.SP.get_auth_url(chat_id)
    assert bot_arg.msg_log[2] == 'There is nothing playing!'

    song = Song('Orphaned land', 'ornaments of gold')
    lyrics = 'The light of the dark is the morning of the dawn'
    monkeypatch.setattr(bot.SP, 'currently_playing', lambda x: song)
    monkeypatch.setattr(bot, 'get_lyrics', lambda x, y: lyrics)
    bot.now(bot_arg, update)
    assert bot_arg.msg_log[3] == lyrics
Beispiel #6
0
def test_getlyrics_from_info():
    """
    Check that the main method can actually return a result with lyrics.
    """
    song = Song(artist='Iron maiden', title='Hallowed be thy name')
    result = get_lyrics(song)
    assert 'hallowed be thy name' in result.song.lyrics.lower()
Beispiel #7
0
def test_argv_from_file(monkeypatch, tmpdir, mp3file):
    """
    Check that the `--from_file` argument can read a text file containing a
    list of filenames, and return a list with all of them.
    """
    mp3_files = [
        tmpdir / 'first.mp3',
        tmpdir / 'second.mp3',
        tmpdir / 'third.mp3',
    ]
    song_tags = [
        ('white wizzard', 'the sun also rises'),
        ('mastodon', 'andromeda'),
        ('megadeth', 'dawn patrol'),
    ]
    songs = []
    for filename, tag in zip(mp3_files, song_tags):
        artist, title = tag
        shutil.copyfile(mp3file, filename)
        tag_mp3(filename, artist=artist, title=title)
        songs.append(Song(artist=artist, title=title))

    filelist = tmpdir / 'filelist'
    with open(filelist, 'w') as file:
        for filename in mp3_files:
            file.write(str(filename) + '\n')
        file.flush()

    monkeypatch.setattr(sys, 'argv', [__file__, '--from-file', str(filelist)])
    parsed_songs = parse_argv()

    assert parsed_songs == set(parsed_songs)
Beispiel #8
0
def test_log_result(database):
    chat_id = 'chat_id'
    song = Song('lucis absentia', 'gehenna gate')
    source = Nothing()
    source.__name__ = 'source'
    result = Nothing()
    result.song = song
    result.source = source

    database.log_result(chat_id, result)
    query = database._execute('select chat_id, source, artist, title from log')
    assert query == dict(chat_id=chat_id,
                         source='source',
                         artist=song.artist,
                         title=song.title)

    source.__name__ = 'new source'
    database.log_result(chat_id, result)
    query = database._execute('select chat_id, source, artist, title from log')
    assert query == dict(
        chat_id=chat_id,
        source='new source',
        artist=song.artist,
        title=song.title,
    )
Beispiel #9
0
def test_run_one_song(mp3file, monkeypatch):
    """
    Test the run() function when passing a single song object. It should call
    get_lyrics_threaded to search for lyrics in all the sources at the same
    time.
    """
    song_lyrics = 'some lyrics here'

    def fake_getlyricsthreaded(songs):
        song.lyrics = song_lyrics
        return Result(song=song, source='whatever', runtimes={})

    song = Song.from_filename(mp3file)
    monkeypatch.setattr(lyricfetch.run, 'get_lyrics_threaded',
                        fake_getlyricsthreaded)
    lyricfetch.run.run(song)
    assert Song.from_filename(mp3file).lyrics == song_lyrics
Beispiel #10
0
def test_spotify_fetch_album_nodiscog(sp_client, monkeypatch):
    """
    Test that the fetch album method returns unknown when we can't find the
    discography for the artist.
    """
    monkeypatch.setattr(sp_client, 'fetch_discography', lambda x: {})
    song = Song('Obscura', 'diluvium')
    assert sp_client.fetch_album(song) == 'Unknown'
Beispiel #11
0
def retrieve_lyrics(track):
    # instantiate song
    song = Song.from_info(track['artist'], track['title'])
    # fetch lyrics
    get_lyrics(song)
    # read lyrics
    lyrics = song.lyrics.split('\n')
    return lyrics
Beispiel #12
0
def test_getlyrics_threaded():
    """
    Test the `get_lyrics_threaded()` function, which should launch a pool of
    processes to search for lyrics in all the available sources, and return the
    result from the first one that returns valid lyrics.
    """
    def source_1(_):
        time.sleep(1)
        return 'Lyrics 1'

    def source_2(_):
        return 'Lyrics 2'

    def source_3(_):
        return ''

    # source_2 is faster than source_1, so we should expect it to return lyrics
    # first, and source_1 to not even be in the result that's returned
    song = Song(artist='Slipknot', title='The virus of life')
    result = get_lyrics_threaded(song, l_sources=[source_1, source_2])
    assert song.lyrics == 'Lyrics 2'
    assert result.song.lyrics == 'Lyrics 2'
    assert result.source == source_2
    assert result.runtimes[source_2] < 1
    assert source_1 not in result.runtimes

    # Now we use source_3, which is faster than source_1, but doesn't return
    # any lyrics, so we expect the function to ignore that result and give us
    # the lyrics from source_1
    song = Song(artist='Power trip', title='Ruination')
    result = get_lyrics_threaded(song, l_sources=[source_1, source_3])
    assert song.lyrics == 'Lyrics 1'
    assert result.song.lyrics == 'Lyrics 1'
    assert result.source == source_1
    assert result.runtimes[source_3] < 1
    assert result.runtimes[source_1] >= 1

    # Lastly, we try only source_3, so we should expect the result to have no
    # lyrics, and its `source` attribute to be None.
    song = Song('Amon amarth', 'Back on northern shores')
    result = get_lyrics_threaded(song, l_sources=[source_3] * 4)
    assert song.lyrics == ''
    assert result.song.lyrics == ''
    assert result.source is None
    assert result.runtimes[source_3] < 1
Beispiel #13
0
def get_song_from_string(song, chat_id):
    """
    Parse the user's input and return a song object from it.
    """
    if not song:
        return None
    if isinstance(song, Song):
        return song

    if '-' in song:
        song = Song.from_string(song)
    else:
        last_res = DB.get_last_res(chat_id)
        if not last_res:
            return None
        song = Song(artist=last_res['artist'], title=song)

    return song
Beispiel #14
0
def test_song_eq_filename():
    """
    Check that song comparison turns out equal when they point to the same file
    name.
    """
    song = Song("Be'lakor", 'Renmants')
    othersong = Song('Carnation', 'Hatred Unleashed')

    song.filename = 'song1.mp3'
    othersong.filename = song.filename
    assert song == othersong
    othersong.filename = Path(song.filename)
    assert song == othersong

    othersong.artist = song.artist
    othersong.title = song.title
    othersong.filename = song.filename + '_nope'
    assert song != othersong
Beispiel #15
0
def test_getlyrics_from_song(mp3file):
    """
    Check that the main method can find the lyrics for a song and write them as
    ID3 metadata.
    """
    tag_mp3(mp3file, artist='YOB', title='Our raw heart')
    song = Song.from_filename(mp3file)
    result = get_lyrics(song)
    assert 'my restless ghost' in result.song.lyrics.lower()
Beispiel #16
0
def test_song_from_string():
    """
    Create a song object from an unparsed string.
    """
    song = Song.from_string('la marea - vetusta morla', reverse=True)
    assert song
    assert song.artist == 'vetusta morla'
    assert song.title == 'la marea'

    song = Song.from_string('els amics de les arts-ja no ens passa')
    assert song
    assert song.artist == 'els amics de les arts'
    assert song.title == 'ja no ens passa'

    song = Song.from_string('immolation / epiphany', separator='/')
    assert song
    assert song.artist == 'immolation'
    assert song.title == 'epiphany'
Beispiel #17
0
def test_process_result(mp3file):
    """
    Check that the `process_result()` function can write the lyrics to the
    corresponding mp3 and return wheter or not they were found.
    """
    artist = 'lör'
    title = 'requiem'
    song_lyrics = 'hello world'
    tag_mp3(mp3file, artist=artist, title=title)
    song = Song.from_filename(mp3file)
    song.lyrics = song_lyrics

    result_notfound = Result(song=song, source=None, runtimes={})
    assert not process_result(result_notfound)
    assert not Song.from_filename(mp3file).lyrics

    result_found = Result(song=song, source='whatever', runtimes={})
    assert process_result(result_found)
    assert Song.from_filename(mp3file).lyrics == song_lyrics
Beispiel #18
0
def test_song_fetch_album_name(lastfm_key):
    """
    Check that a song can retrieve the album name if it's not given.
    """
    song = Song(artist='Barren earth', title='The living fortress')
    assert song.album == ''
    song.fetch_album_name()
    assert song.album.lower() == 'a complex of cages'

    song = Song(artist='Dropkick Murphys', title='asdfasdfasdf')
    song.fetch_album_name()
    assert song.album == ''
Beispiel #19
0
def test_run_multiple_songs(mp3file, monkeypatch):
    """
    Test the run() function when passing multiple songs. This time it should
    call run_mp() on the entire collection.
    """
    def fake_runmp(songs):
        for i, song in enumerate(songs):
            tag_mp3(song.filename, lyrics=f'lyrics{i}')
        return Stats()

    other_mp3 = tempfile.mktemp()
    shutil.copy(mp3file, other_mp3)
    mp3files = [mp3file, other_mp3]
    songs = [Song.from_filename(f) for f in mp3files]
    CONFIG['print_stats'] = False
    monkeypatch.setattr(lyricfetch.run, 'run_mp', fake_runmp)
    lyricfetch.run.run(songs)
    for i, filename in enumerate(mp3files):
        assert Song.from_filename(filename).lyrics == f'lyrics{i}'
Beispiel #20
0
def test_get_lyrics_found(monkeypatch, bot):
    song = Song('obituary', 'ten thousand ways to die', lyrics='lyrics')

    monkeypatch.setattr(bot, 'get_lyrics_threaded', lambda a, b: fake_log)
    msg = bot.get_lyrics(song, 1).lower()
    assert fake_res['source'].lower() in msg
    assert song.title in msg
    assert song.artist in msg
    assert song.lyrics in msg
    assert bot.DB.get_last_res(1)
Beispiel #21
0
def test_getlyrics_dont_overwrite(mp3file):
    """
    Check that we skip a song if the mp3 file already has embedded lyrics.
    """
    placeholder = 'Some lyrics'
    tag_mp3(mp3file, lyrics=placeholder)

    song = Song.from_filename(mp3file)
    CONFIG['overwrite'] = False
    assert get_lyrics(song) is None
    assert song.lyrics == placeholder
Beispiel #22
0
def test_album_tracks_lastfm_notfound(bot, monkeypatch):
    """
    Test get_album_tracks_lastfm when the album isn't found in the lastfm
    database.
    """
    def get_lastfm(*args, **kwargs):
        return []

    song = Song('Horrendous', 'The Idolater', album='Idol')
    monkeypatch.setattr(bot, 'get_lastfm', get_lastfm)
    assert bot.get_album_tracks_lastfm(song) == []
Beispiel #23
0
def test_song_init():
    """
    Create a song object with a set of parameters.
    """
    song = Song('Opeth', 'Bleak', 'Blackwater Park')
    assert song
    assert song.artist == 'Opeth'
    assert song.title == 'Bleak'
    assert song.album == 'Blackwater Park'
    assert song.lyrics == ''
    assert not hasattr(song, 'filename')
Beispiel #24
0
def test_get_song_from_string_lastres(bot):
    """
    Test get a song from string when there is no hyphen and we must get the
    last result from the database.
    """
    chat_id = 'chat_id'
    assert bot.get_song_from_string('', chat_id) is None

    song = Song(fake_res['artist'], 'the spectral burrows')
    bot.log_result(chat_id, fake_log)
    assert get_song_from_string('the spectral burrows', chat_id) == song
Beispiel #25
0
def test_album_tracks(bot, monkeypatch):
    """
    Check that bot.get_album_tracks() searches spotify first, and uses lastfm
    as a fallback.
    """
    song = Song('wintersun', 'beyond the dark sun')
    monkeypatch.setattr(bot.SP, 'get_album_tracks', lambda x: [])
    monkeypatch.setattr(bot, 'get_album_tracks_lastfm', lambda x: ['lastfm'])
    assert bot.get_album_tracks(song)[0] == 'lastfm'

    monkeypatch.setattr(bot.SP, 'get_album_tracks', lambda x: ['spotify'])
    assert get_album_tracks(song)[0] == 'spotify'
Beispiel #26
0
def test_getlyrics_overwrite(mp3file):
    """
    Check that we can overwrite the lyrics of a song if it already has them.
    """
    placeholder = 'Some lyrics'
    tag_mp3(mp3file, artist='Baroness', title='Eula', lyrics=placeholder)

    song = Song.from_filename(mp3file)
    CONFIG['overwrite'] = True
    result = get_lyrics(song)
    assert result.song.lyrics != placeholder
    assert 'forget the taste of my own tongue' in result.song.lyrics.lower()
Beispiel #27
0
def fake_getlyrics_run_mp(source):
    """
    Convenience function to replace the standard `get_lyrics()` that is used by
    `test_run_mp()`.
    """
    time.sleep(1)
    if source is False:
        return None

    runtimes = {azlyrics: 1}
    song = Song(artist='breaking benjamin', title='i will not bow')
    return Result(song, source, runtimes)
Beispiel #28
0
def test_spotify_get_album_tracks_noalbum(sp_client, monkeypatch):
    """
    Test getting the list of album tracks when the given song already has an
    album attribute.
    """
    album = 'marrow'
    song = Song('madder mortem', 'tethered')
    monkeypatch.setattr(sp_client, 'fetch_album', lambda x: album)

    song_list = ['tethered', 'liberator']
    sp_client.discography_cache = {song.artist: {album: {'tracks': song_list}}}
    assert song_list == sp_client.get_album_tracks(song)
Beispiel #29
0
def test_next_song_existing(bot, monkeypatch):
    """
    Test the _get_next_song existing when everything goes smoothly and the next
    song is found.
    """
    tracks = [fake_res['title'], 'war squids']
    song_next = Song(fake_res['artist'], 'war squids', fake_res['album'])
    bot.log_result('chat_id', fake_log)
    monkeypatch.setattr(bot, 'get_album_tracks', lambda x: tracks)
    monkeypatch.setattr(bot, 'get_lyrics', lambda s, c: f'Searching for {s}')

    assert bot._get_next_song('chat_id') == f'Searching for {song_next}'
Beispiel #30
0
def test_next_song(monkeypatch, bot, bot_arg, update):
    """
    Test the next_song function, in a similar manner to _get_next_song.
    """
    tracks = [fake_res['title'], 'crop killer']
    song_next = Song(fake_res['artist'], 'crop killer', fake_res['album'])
    bot.log_result('chat_id', fake_log)
    monkeypatch.setattr(bot, 'get_album_tracks', lambda x: tracks)
    monkeypatch.setattr(bot, 'get_lyrics', lambda s, c: f'Searching for {s}')

    next_song(bot_arg, update)
    assert bot_arg.msg_log[0] == f'Searching for {song_next}'