Add spotify search (only search), default menu

This commit is contained in:
BarsTiger
2023-10-16 20:17:10 +03:00
parent c63d8795aa
commit b515fdfd65
18 changed files with 256 additions and 4 deletions

View File

@@ -4,10 +4,11 @@ from rich import print
async def runner():
from .common import dp, bot
from . import handlers
from . import handlers, callbacks
dp.include_router(
handlers.router
dp.include_routers(
handlers.router,
callbacks.router,
)
await bot.delete_webhook(drop_pending_updates=True)

View File

@@ -0,0 +1,14 @@
from aiogram import Router
from . import (
full_menu,
)
from bot.middlewares import PrivateButtonMiddleware
router = Router()
router.callback_query.middleware(PrivateButtonMiddleware())
router.include_routers(
full_menu.router,
)

View File

@@ -0,0 +1,6 @@
from typing import Literal
from aiogram.filters.callback_data import CallbackData
class FullMenuCallback(CallbackData, prefix='full_menu'):
action: Literal['settings']

View File

@@ -0,0 +1,12 @@
from aiogram import Router, Bot, F
from aiogram.types import (
CallbackQuery
)
from .factories.full_menu import FullMenuCallback
router = Router()
@router.callback_query(FullMenuCallback.filter(F.action == 'settings'))
async def on_close(callback_query: CallbackQuery, bot: Bot):
await callback_query.answer('Settings are not available yet')

View File

@@ -1,9 +1,20 @@
from aiogram import Router
from . import initialize
from . import (
initialize,
inline_default,
inline_empty,
on_chosen,
)
from bot.middlewares import SaveChosenMiddleware
router = Router()
router.chosen_inline_result.outer_middleware(SaveChosenMiddleware())
router.include_routers(
initialize.router,
inline_default.router,
inline_empty.router,
on_chosen.router,
)

View File

@@ -0,0 +1 @@
from .on_inline_default import router

View File

@@ -0,0 +1,38 @@
from aiogram import Router, Bot, F
from aiogram.types import (
InlineQuery, InlineQueryResultDocument, InlineQueryResultCachedAudio,
InlineKeyboardMarkup, InlineKeyboardButton,
)
from bot.modules.spotify import spotify
from bot.modules.database import db
router = Router()
@router.inline_query(F.query != '')
async def default_inline_query(inline_query: InlineQuery, bot: Bot):
await inline_query.answer(
[
InlineQueryResultDocument(
id='spot::' + audio.id,
title=audio.name,
description=audio.all_artists,
thumb_url=audio.thumbnail,
document_url=audio.preview_url,
mime_type='application/zip',
reply_markup=InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text='Downloading...', callback_data='.')]
]
)
) if audio.id not in list(db.spotify.keys()) else
InlineQueryResultCachedAudio(
id='spotc::' + audio.id,
audio_file_id=db.spotify[audio.id],
)
for audio in spotify.songs.search(inline_query.query)
],
cache_time=0,
is_personal=True
)

View File

@@ -0,0 +1 @@
from .on_inline_empty import router

View File

@@ -0,0 +1,23 @@
from aiogram import Router, Bot, F
from aiogram.types import (
InlineQuery, InputTextMessageContent, InlineQueryResultArticle
)
from bot.keyboards.inline.full_menu import get_full_menu_kb
router = Router()
@router.inline_query(F.query == '')
async def empty_inline_query(inline_query: InlineQuery, bot: Bot):
await inline_query.answer(
[
InlineQueryResultArticle(
id='show_menu',
title='⚙️ Open menu',
input_message_content=InputTextMessageContent(
message_text='⚙️ Menu'
),
reply_markup=get_full_menu_kb()
)
], cache_time=0
)

View File

@@ -0,0 +1 @@
from .spotify import router

View File

@@ -0,0 +1,35 @@
from aiogram import Router, Bot, F
from aiogram.types import (
FSInputFile, URLInputFile, InputMediaAudio,
ChosenInlineResult,
)
from bot.modules.spotify import spotify
from rich import print
from bot.utils.config import config
from bot.modules.database import db
router = Router()
@router.chosen_inline_result(F.result_id.startswith('spot::'))
async def on_new_chosen(chosen_result: ChosenInlineResult, bot: Bot):
print('TEST: DOWNLOADING NEW')
song = spotify.songs.from_id(chosen_result.result_id.removeprefix('spot::'))
audio = await bot.send_audio(
chat_id=config.telegram.files_chat,
audio=FSInputFile('tests/test.mp3'),
thumbnail=URLInputFile(song.thumbnail),
performer=song.all_artists,
title=song.name,
)
db.spotify[song.id] = audio.audio.file_id
await db.occasionally_write()
await bot.edit_message_media(
inline_message_id=chosen_result.inline_message_id,
media=InputMediaAudio(media=audio.audio.file_id),
reply_markup=None
)

View File

@@ -0,0 +1,22 @@
from aiogram.utils.keyboard import (InlineKeyboardMarkup, InlineKeyboardButton,
InlineKeyboardBuilder)
from bot.callbacks.factories.full_menu import FullMenuCallback
def get_full_menu_kb() -> InlineKeyboardMarkup:
buttons = [
[
InlineKeyboardButton(
text='⚙️ Settings',
callback_data=FullMenuCallback(
action='settings'
).pack()
),
InlineKeyboardButton(
text='🎵 Search in SoundCloud',
switch_inline_query_current_chat='sc::'
)
]
]
return InlineKeyboardBuilder(buttons).as_markup()

View File

@@ -0,0 +1,2 @@
from .private_button import PrivateButtonMiddleware
from .save_chosen import SaveChosenMiddleware

View File

@@ -0,0 +1,19 @@
from aiogram.dispatcher.middlewares.base import BaseMiddleware
from aiogram.types import CallbackQuery
from typing import Any, Awaitable, Callable, Dict
from bot.modules.database import db
class PrivateButtonMiddleware(BaseMiddleware):
async def __call__(
self,
handler: Callable[[CallbackQuery, Dict[str, Any]], Awaitable[Any]],
event: CallbackQuery,
data: Dict[str, Any],
):
if event.from_user.id == db.inline[event.inline_message_id].from_user.id:
return await handler(event, data)
else:
await event.answer('This button is not for you')

View File

@@ -0,0 +1,46 @@
from aiogram.dispatcher.middlewares.base import BaseMiddleware
from aiogram.types import ChosenInlineResult
from typing import Any, Awaitable, Callable, Dict
from dataclasses import dataclass
from bot.modules.database import db
@dataclass
class SavedUser:
id: int
first_name: str
last_name: str | None
username: str | None
language_code: str | None
@dataclass
class SavedResult:
result_id: str
from_user: SavedUser
query: str
inline_message_id: str
class SaveChosenMiddleware(BaseMiddleware):
async def __call__(
self,
handler: Callable[[ChosenInlineResult, Dict[str, Any]], Awaitable[Any]],
event: ChosenInlineResult,
data: Dict[str, Any],
):
db.inline[event.inline_message_id] = SavedResult(
result_id=event.result_id,
from_user=SavedUser(
id=event.from_user.id,
first_name=event.from_user.first_name,
last_name=event.from_user.last_name,
username=event.from_user.username,
language_code=event.from_user.language_code
),
query=event.query,
inline_message_id=event.inline_message_id
)
return await handler(event, data)

View File

@@ -2,6 +2,8 @@ from .db_model import DBDict
import os.path
from bot.utils.config import config
from random import randint
DB = os.path.join(config.local.db_path, 'db')
if not os.path.isfile(DB):
@@ -12,6 +14,12 @@ class Db(object):
def __init__(self):
self.fsm = DBDict('fsm')
self.config = DBDict('config')
self.inline = DBDict('inline')
self.spotify = DBDict('spotify')
async def write(self):
await self.config.write()
async def occasionally_write(self, chance: int = 5):
if randint(1, chance) == 1:
await self.write()

View File

@@ -24,6 +24,10 @@ class SongItem:
def all_artists(self):
return ', '.join(self.artists)
@property
def full_name(self):
return f"{self.all_artists} - {self.name}"
def __str__(self):
return f"{', '.join(self.artists)} - {self.name}"
@@ -39,3 +43,11 @@ class Songs(object):
return None
return [SongItem.from_spotify(item) for item in r['tracks']['items']]
def from_id(self, song_id: str) -> SongItem | None:
r = self.spotify.track(song_id)
if r is None:
return None
return SongItem.from_spotify(r)

View File