Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly get_full_info for songs and albums #181

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

Steffo99
Copy link

Previously, the full song info wasn't fetched, as song_id never was None, and the check if song_id is None stopped the retrieval from executing.

I corrected that line, and added the new fields to the Song type; some of them should probably have a corresponding type too, but I don't currently have time to implement them right now.

Previously, it was fetched only when the song didn't have an id (?)
@allerter allerter self-assigned this Feb 10, 2021
@allerter
Copy link
Collaborator

Hi. Thanks for contributing to LyricsGenius. The if song_id is None was meant to avoid fetching the song twice in case the user had provided a song ID. But as you mentioned, the song_id is never None. I had a look and the same thing also happens in search_album as well.
Although your solution solves the problem, now there will be a redundant request if the user provides a song_id in the first place. I suggest keeping the if statement as it is, but moving it before song_id gets overwritten.
As for the second part of your PR concerning the new fields, we were reluctant to add more fields because the value of some fields could be misleading. For example, what does a None value for Song.featured_video mean? Does it mean the Song had no featured video, or it just wasn't in the request dict? That's why we avoided adding more fields to Song.

@allerter
Copy link
Collaborator

For the Song fields, I can think of two ways:

  • Removing get_full_info altogether and update Song to have all fields.

or:

  • Breaking Song into two types: SearchSong and FullSong.

What do you think, @johnwmillr?

@Steffo99
Copy link
Author

For example, what does a None value for Song.featured_video mean? Does it mean the Song had no featured video, or it just wasn't in the request dict? That's why we avoided adding more fields to Song.

Another solution might be to use Ellipsis (...) for values which weren't retrieved, allowing them to be distinguished from None/null values returned from the API.

lyricsgenius/genius.py Outdated Show resolved Hide resolved
@allerter
Copy link
Collaborator

Your PR is about ready. Just apply the change in the last conversation and remove the changes to song.py.

@Steffo99 Steffo99 changed the title Properly get_full_info for songs Properly get_full_info for songs and albums Feb 14, 2021
@Steffo99
Copy link
Author

Steffo99 commented Feb 14, 2021

@allerter I've done as you asked.

I checked, and confirm that search_artists isn't affected by this bug. (I found a few unused statements that I will probably fix in a future pull request.)

Thanks for your time!

@Steffo99 Steffo99 marked this pull request as ready for review February 14, 2021 04:08
lyricsgenius/genius.py Outdated Show resolved Hide resolved
lyricsgenius/genius.py Outdated Show resolved Hide resolved
lyricsgenius/genius.py Outdated Show resolved Hide resolved
lyricsgenius/genius.py Outdated Show resolved Hide resolved
@allerter allerter added the bug label Feb 16, 2021
Copy link
Collaborator

@allerter allerter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. I think it's good to go.

@allerter allerter added this to the 3.0.1 milestone Apr 21, 2021
@allerter
Copy link
Collaborator

@johnwmillr, could you please review and merge this?

@Lionheartxx
Copy link

@johnwmillr, could you please review and merge this?

Hi Dear @allerter
I have the same error!!!
If i deploy my telegram bot project to server i get 403 forbidden error but when i run local in PyCharm everything works
This my Code:

import numpy as np
from requests.exceptions import HTTPError, Timeout
import lyricsgenius

from aiogram import types
from data.config import GENIUS_ACCESS_TOKEN,GENIUS_CLIENT_ID,GENIUS_CLIENT_SECRET,GENIUS_REDIRECT_URI
from keyboards.inline.SelectButton import SelectSong
from aiogram.types import CallbackQuery
from aiogram.dispatcher.filters import Command
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.dispatcher import FSMContext

from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session

from loader import dp

class OAuth2Genius(StatesGroup):
    waiting_for_code = State()


GENIUS_API_BASE_URL = 'https://api.genius.com'

def create_genius_session(token=None, state=None):
    client = BackendApplicationClient(client_id=GENIUS_CLIENT_ID)
    genius3 = OAuth2Session(client=client, token=token, redirect_uri=GENIUS_REDIRECT_URI, state=state)
    return genius3

@dp.message_handler(Command("start"))
async def start_auth(message: types.Message):
    # Start the Genius OAuth2 flow
    genius3 = create_genius_session()
    authorization_url, state = genius3.authorization_url('https://api.genius.com/oauth/authorize')

    await message.answer("To authorize, click on this [link]({})".format(authorization_url), parse_mode='Markdown')
    await OAuth2Genius.waiting_for_code.set()

@dp.message_handler(state=OAuth2Genius.waiting_for_code)
async def receive_auth_code(message: types.Message, state: FSMContext):
    # Receive the Genius OAuth2 code and exchange it for a token
    genius3 = create_genius_session(state=state)
    token = genius3.fetch_token('https://api.genius.com/oauth/token', authorization_response=message.text,
                               client_secret=GENIUS_CLIENT_SECRET)

    # Save the token to use later in your requests
    await state.finish()
    await message.answer("Authorization successful! You can now use Genius API.")
    # Store the token somewhere secure for future use (e.g., a database)

    global genius2
    genius2 = create_genius_session(token=token)

genius = lyricsgenius.Genius(GENIUS_ACCESS_TOKEN)
numbered_songs = []

@dp.message_handler()
async def Send_List(message: types.Message):
    def ListOfSongs(search_songs):
        try:
            song = genius.search_songs(f"{search_songs}")

            list_of_artist = []
            list_of_song = []

            for hit in song['hits']:
                list_of_artist.append(hit['result']['primary_artist']['name'])
                list_of_song.append(hit['result']['title'])

            arr = np.dstack((list_of_artist, list_of_song))
            len_arr = len(arr[0])

            for res in arr[0][range(0, len_arr)]:
                numbered_songs.append(f"{res[0]} - {res[1]}")

        except HTTPError as e:
            print(e.errno)
            print(e.args[0])
            print(e.args[1])
        except Timeout:
            pass

    if len(numbered_songs) == 0:
        ListOfSongs(search_songs=message.text)
    else:
        numbered_songs.clear()
        ListOfSongs(search_songs=message.text)

    result_count = min(len(numbered_songs), 10)

    if result_count >= 1:
        await message.answer(
            f"<b>Результаты 1-{result_count}</b>\n\n"
            + "\n".join(f"{i + 1}.  {numbered_songs[i]}" for i in range(result_count)),
            reply_markup=SelectSong
        )
    else:
        await message.answer("Такой песен не найдено 🤔")

@dp.callback_query_handler(lambda call: call.data.isdigit())
async def Send_Lyric(call: CallbackQuery):
    index = int(call.data)

    if 1 <= index <= len(numbered_songs):
        await call.message.delete()
        await call.message.answer("🔎 Ищу тексты песен...")

        full_text = await GetText(numbered_songs[index - 1])

        if full_text:
            # Telegramning maksimal belgilar soni 4040 ta
            if len(full_text) <= 4020:
                await call.message.answer(full_text)
            else:
                short_text = full_text[:4020]
                await call.message.answer(short_text + f"...\n\n<i>через @MusixMBot</i>")
        else:
            await call.message.answer("Извините, такого текста не найдено 🫥")

async def GetText(song_name):
    artist_name, song_get_name = map(str.strip, song_name.split("-"))

    try:
        artist = genius.search_artist(artist_name, max_songs=1)
        song_text = artist.song(song_get_name)
        text = song_text.lyrics

        return f"<code>{artist_name} - {song_get_name}</code>\n\n{text[:-5]}\n\n<i>через @MusixMBot</i>"

    except HTTPError as e:
        print(e.errno)
        print(e.args[0])
        print(e.args[1])

    except Timeout:
        pass

    return None

image

I used the liyricsgenius package. But I don't know how to integrate Genius authentication method into Code. If anyone knows, please help!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants