mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-18 23:24:18 +02:00
Compare commits
2 Commits
update-sub
...
e2ff44c2e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2ff44c2e0 | ||
|
|
bfeb11ff53 |
@@ -26,7 +26,6 @@ from .. import loader, utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Banners:
|
class Banners:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -324,6 +323,16 @@ class YaMusicMod(loader.Module):
|
|||||||
"name": "YaMusic"
|
"name": "YaMusic"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duration_placeholder = {
|
||||||
|
"start_duration": "<tg-emoji emoji-id=5262663495538742892>☀️</tg-emoji><tg-emoji emoji-id=5260381609479153468>☀️</tg-emoji>",
|
||||||
|
"start_full_duration": "<tg-emoji emoji-id=5262663495538742892>☀️</tg-emoji><tg-emoji emoji-id=5260609582048254485>☀️</tg-emoji>",
|
||||||
|
"closed_duration": "<tg-emoji emoji-id=5260467667738859177>☀️</tg-emoji>",
|
||||||
|
"empty_mid": "<tg-emoji emoji-id=5260415715814448198>☀️</tg-emoji>",
|
||||||
|
"empty_closed_duration_duration": "<tg-emoji emoji-id=5260239235608255208>☀️</tg-emoji>",
|
||||||
|
"end_duration_full": "<tg-emoji emoji-id=5260467667738859177>☀️</tg-emoji>",
|
||||||
|
"empty_closed_duration": "<tg-emoji emoji-id=5260239235608255208>☀️</tg-emoji>",
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.config = loader.ModuleConfig(
|
self.config = loader.ModuleConfig(
|
||||||
loader.ConfigValue(
|
loader.ConfigValue(
|
||||||
@@ -553,67 +562,19 @@ class YaMusicMod(loader.Module):
|
|||||||
return "0%"
|
return "0%"
|
||||||
|
|
||||||
percent = (progress / duration) * 100
|
percent = (progress / duration) * 100
|
||||||
|
fill_logic = int(percent // 16.66)
|
||||||
|
|
||||||
s_less_10 = (
|
bar = self.duration_placeholder["start_full_duration"] if fill_logic >= 1 else self.duration_placeholder["start_duration"]
|
||||||
"<emoji document_id=5454137780454067986>➖</emoji>"
|
for i in range(2, 6):
|
||||||
"<emoji document_id=6158923355173949539>⭐</emoji>"
|
if fill_logic >= i:
|
||||||
"<emoji document_id=6159012102083188132>⭐</emoji>"
|
bar += self.duration_placeholder["closed_duration"]
|
||||||
"<emoji document_id=6159012102083188132>⭐</emoji>"
|
else:
|
||||||
"<emoji document_id=6158753257289158944>⭐</emoji>"
|
bar += self.duration_placeholder["empty_mid"]
|
||||||
"<emoji document_id=6156700344526049665>⭐</emoji>"
|
if fill_logic >= 6:
|
||||||
)
|
bar += self.duration_placeholder["end_duration_full"]
|
||||||
|
|
||||||
s_10_to_20 = (
|
|
||||||
"<emoji document_id=5454137780454067986>➖</emoji>"
|
|
||||||
"<emoji document_id=6159095673556840262>⭐</emoji>"
|
|
||||||
"<emoji document_id=6159012102083188132>⭐</emoji>"
|
|
||||||
"<emoji document_id=6156933677214341691>⭐</emoji>"
|
|
||||||
"<emoji document_id=6158753257289158944>⭐</emoji>"
|
|
||||||
"<emoji document_id=6156700344526049665>⭐</emoji>"
|
|
||||||
)
|
|
||||||
|
|
||||||
s_30_to_40 = (
|
|
||||||
"<emoji document_id=5454137780454067986>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=6158923355173949539>⭐</emoji>"
|
|
||||||
"<emoji document_id=6159012102083188132>⭐</emoji>"
|
|
||||||
"<emoji document_id=6156700344526049665>⭐</emoji>"
|
|
||||||
)
|
|
||||||
|
|
||||||
s_over_50 = (
|
|
||||||
"<emoji document_id=5454137780454067986>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=6156933677214341691>⭐</emoji>"
|
|
||||||
"<emoji document_id=6156700344526049665>⭐</emoji>"
|
|
||||||
)
|
|
||||||
|
|
||||||
s_over_80 = (
|
|
||||||
"<emoji document_id=5454137780454067986>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=5454397458471750662>➖</emoji>"
|
|
||||||
"<emoji document_id=6156700344526049665>⭐</emoji>"
|
|
||||||
)
|
|
||||||
|
|
||||||
if percent < 10:
|
|
||||||
return s_less_10
|
|
||||||
elif percent < 20:
|
|
||||||
return s_10_to_20
|
|
||||||
elif percent < 30:
|
|
||||||
return s_10_to_20
|
|
||||||
elif percent < 40:
|
|
||||||
return s_30_to_40
|
|
||||||
elif percent < 50:
|
|
||||||
return s_30_to_40
|
|
||||||
elif percent < 80:
|
|
||||||
return s_over_50
|
|
||||||
else:
|
else:
|
||||||
return s_over_80
|
bar += self.duration_placeholder["empty_closed_duration"]
|
||||||
|
return bar
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error: {e}"
|
return f"Error: {e}"
|
||||||
|
|
||||||
|
|||||||
260
modules.json
260
modules.json
@@ -18,18 +18,199 @@
|
|||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
"LimokaLegacy.py": {
|
"LimokaLegacy.py": {
|
||||||
"name": "LimokaLegacy",
|
"name": "Limoka",
|
||||||
"description": "",
|
"description": "Modules are now in one place with easy searching!",
|
||||||
"cls_doc": {},
|
"cls_doc": {
|
||||||
|
"ru": "Модули теперь в одном месте с простым и удобным поиском!"
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"pic": null,
|
"pic": null,
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"developer": "@limokanews"
|
"developer": "@limokanews"
|
||||||
},
|
},
|
||||||
"commands": [],
|
"commands": [
|
||||||
"new_commands": [],
|
{
|
||||||
|
"limoka": "[query / nothing] - Search modules | (RU) [запрос / ничего] — Поиск модулей"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lshistory": "[clear] - Show or clear search history | (RU) [clear] — Показать или очистить историю поиска"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"new_commands": [
|
||||||
|
{
|
||||||
|
"name": "limoka",
|
||||||
|
"original_name": "limokacmd",
|
||||||
|
"description": {
|
||||||
|
"default": "[query / nothing] - Search modules",
|
||||||
|
"ru": "[запрос / ничего] — Поиск модулей"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lshistory",
|
||||||
|
"original_name": "lshistorycmd",
|
||||||
|
"description": {
|
||||||
|
"default": "[clear] - Show or clear search history",
|
||||||
|
"ru": "[clear] — Показать или очистить историю поиска"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
"inline_handlers": [],
|
"inline_handlers": [],
|
||||||
"strings": {},
|
"strings": {
|
||||||
|
"name": "Limoka",
|
||||||
|
"wait": "<blockquote>Just wait\n<emoji document_id=5404630946563515782>🔍</emoji> A search is underway among {count} modules for the query: <code>{query}</code>\n<i>{fact}</i></blockquote>",
|
||||||
|
"found_header": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> Found module <b>{name}</b> by query: <b>{query}</b>\n\n<b><emoji document_id=5418376169055602355>ℹ️</emoji> Description:</b> {description}\n<b><emoji document_id=5418299289141004396>🧑💻</emoji> Developer:</b> {username}\n\n<b><emoji document_id=5418376169055602355>🏷</emoji> Tags:</b> {tags}\n\n</blockquote>",
|
||||||
|
"found_body": "{commands}",
|
||||||
|
"found_footer": "<blockquote>\n<emoji document_id=5411143117711624172>🪄</emoji> <code>{prefix}dlm {url}{module_path}</code></blockquote>",
|
||||||
|
"caption_short": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>{safe_name}</b>\n<b><emoji document_id=5418376169055602355>ℹ️</emoji> Description:</b> {safe_desc}\n<b><emoji document_id=5418299289141004396>🧑💻</emoji> Dev:</b> {dev_username}\n<emoji document_id=5411143117711624172>🪄</emoji> <code>{prefix}dlm {module_path}</code></blockquote>",
|
||||||
|
"command_template": "{emoji} <code>{prefix}{command}</code> — {description}\n",
|
||||||
|
"inline_handler_template": "{inline_bot} {command} — {description}\n",
|
||||||
|
"emojis": {
|
||||||
|
"1": "<emoji document_id=5416037945909987712>1️⃣</emoji>",
|
||||||
|
"2": "<emoji document_id=5413855071731470617>2️⃣</emoji>",
|
||||||
|
"3": "<emoji document_id=5416068826724850291>3️⃣</emoji>",
|
||||||
|
"4": "<emoji document_id=5415843998071803071>4️⃣</emoji>",
|
||||||
|
"5": "<emoji document_id=5415684843763686989>5️⃣</emoji>",
|
||||||
|
"6": "<emoji document_id=5415975458430796879>6️⃣</emoji>",
|
||||||
|
"7": "<emoji document_id=5415769763857060166>7️⃣</emoji>",
|
||||||
|
"8": "<emoji document_id=5416006506749383505>8️⃣</emoji>",
|
||||||
|
"9": "<emoji document_id=5415963015910544694>9️⃣</emoji>"
|
||||||
|
},
|
||||||
|
"404": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>Not found by query: <i>{query}</i></b></blockquote>",
|
||||||
|
"noargs": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>No args</b></blockquote>",
|
||||||
|
"?": "<blockquote><emoji document_id=5951895176908640647>🔎</emoji> Request too short / not found</blockquote>",
|
||||||
|
"no_info": "<blockquote>No information</blockquote>",
|
||||||
|
"facts": [
|
||||||
|
"<blockquote><emoji document_id=5472193350520021357>🛡</emoji> The limoka catalog is carefully moderated!</blockquote>",
|
||||||
|
"<blockquote><emoji document_id=5940434198413184876>🚀</emoji> Limoka performance allows you to search for modules quickly!</blockquote>"
|
||||||
|
],
|
||||||
|
"inline404": "<blockquote>Not found</blockquote>",
|
||||||
|
"inline?": "<blockquote>Request too short / not found</blockquote>",
|
||||||
|
"inlinenoargs": "<blockquote>Please, enter query</blockquote>",
|
||||||
|
"history": "<blockquote><emoji document_id=5879939498149679716>🔎</emoji> <b>Your search history:</b>\n{history}</blockquote>",
|
||||||
|
"filter_menu": "Choose filters",
|
||||||
|
"filter_cat": "📑 Filter by Category",
|
||||||
|
"apply_filters": "✅ Apply Filters",
|
||||||
|
"clear_filters": "🗑 Clear Filters",
|
||||||
|
"back_to_results": "🔙 Back to Results",
|
||||||
|
"empty_history": "<blockquote><emoji document_id=5879939498149679716>🔎</emoji> <b>Your search history is empty!</b></blockquote>",
|
||||||
|
"enter_query": "<blockquote>🔍 Enter new search query:</blockquote>",
|
||||||
|
"global_search": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> Global search for <b>{query}</b> — found <b>{count}</b> modules</blockquote>",
|
||||||
|
"change_query": "🔍 Change query",
|
||||||
|
"no_modules": "<blockquote>No modules available.</blockquote>",
|
||||||
|
"filter_title": "🏷 Filters",
|
||||||
|
"category_title": "📂 Categories",
|
||||||
|
"selected_categories": "<blockquote>✅ Selected categories: {categories}</blockquote>",
|
||||||
|
"no_categories": "<blockquote>No categories found in the module database</blockquote>",
|
||||||
|
"select_category": "<blockquote>Select categories for query: <code>{query}</code>\n(You can select multiple)</blockquote>",
|
||||||
|
"back": "🔙 Back",
|
||||||
|
"category": "📁 {category}",
|
||||||
|
"no_category": "<blockquote>No category</blockquote>",
|
||||||
|
"global_button": "🌍 Results",
|
||||||
|
"filtered_button": "🏷️ Filtered search",
|
||||||
|
"inline_search": "🔍 Search in Limoka",
|
||||||
|
"inline_no_results": "<blockquote>❌ No modules found</blockquote>",
|
||||||
|
"inline_error": "<blockquote>❌ Search error occurred</blockquote>",
|
||||||
|
"inline_short_query": "<blockquote>❌ Query too short (min 2 chars)</blockquote>",
|
||||||
|
"inline_switch_pm": "💬 Open in chat",
|
||||||
|
"inline_switch_pm_text": "🔍 Results for: {query}",
|
||||||
|
"inline_start_message": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Limoka Search</b>\nType module name or keyword</blockquote>",
|
||||||
|
"first_page": "<blockquote>This is the first page!</blockquote>",
|
||||||
|
"last_page": "<blockquote>This is the last page!</blockquote>",
|
||||||
|
"display_error": "<blockquote>Error displaying module. Please try again.</blockquote>",
|
||||||
|
"error_occurred": "<blockquote>An error occurred. Please try again.</blockquote>",
|
||||||
|
"start_search_form": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Limoka Search</b>\nEnter your query to search for modules:</blockquote>",
|
||||||
|
"global_search_form": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Global Search</b>\nEnter your query to search ALL modules without filters:</blockquote>",
|
||||||
|
"history_cleared": "<blockquote><emoji document_id=5427009710268689068>🧹</emoji> <b>Search history cleared!</b></blockquote>",
|
||||||
|
"invalid_history_arg": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>Invalid argument for history command. Use:</b>\n<code>.lshistory</code> - show history\n<code>.lshistory clear</code> - clear history</blockquote>",
|
||||||
|
"close": "❌ Close",
|
||||||
|
"watcher_no_tag": "<blockquote>❌ Invalid message format. No #limoka tag found.</blockquote>",
|
||||||
|
"watcher_invalid_format": "<blockquote>❌ Invalid format. Expected: #limoka:path:signature</blockquote>",
|
||||||
|
"watcher_signature_invalid": "<blockquote>❌ Signature invalid! Installation aborted.</blockquote>",
|
||||||
|
"watcher_loader_missing": "<blockquote>❌ Loader module not found.</blockquote>",
|
||||||
|
"watcher_module_not_found": "<blockquote>❌ Module not found in Limoka database: <code>{path}</code></blockquote>",
|
||||||
|
"watcher_critical": "<blockquote>❌ Critical error: {error}</blockquote>",
|
||||||
|
"tags": {
|
||||||
|
"herokutrusted": "Heroku Trusted",
|
||||||
|
"hikkatrusted": "Hikka Trusted",
|
||||||
|
"nonactive": "Non-Active Repository",
|
||||||
|
"nonlongermaintained": "No Longer Maintained Repository",
|
||||||
|
"newbie": "Newbie"
|
||||||
|
},
|
||||||
|
"indexing_in_progress": "<blockquote>⚠️ Database is busy, try again later. If issue persists, try removing limoka_index in the userbot's root folder. If error persists again, report to developers</blockquote>",
|
||||||
|
"body_page": "Commands",
|
||||||
|
"name_ru": "Limoka",
|
||||||
|
"wait_ru": "<blockquote>Подождите\n<emoji document_id=5404630946563515782>🔍</emoji> Идёт поиск среди {count} модулей по запросу: <code>{query}</code>\n<i>{fact}</i></blockquote>",
|
||||||
|
"found_header_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> Найден модуль <b>{name}</b> по запросу: <b>{query}</b></blockquote>\n\n<blockquote><b><emoji document_id=5418376169055602355>ℹ️</emoji> Описание:</b> {description}</blockquote>\n<blockquote><b><emoji document_id=5418299289141004396>🧑💻</emoji> Разработчик:</b> {username}</blockquote>\n\n<blockquote><b><emoji document_id=5418376169055602355>🏷</emoji> Теги:</b> {tags}</blockquote>\n\n",
|
||||||
|
"found_body_ru": "{commands}",
|
||||||
|
"found_footer_ru": "\n<blockquote><emoji document_id=5411143117711624172>🪄</emoji> <code>{prefix}dlm {url}{module_path}</code></blockquote>",
|
||||||
|
"caption_short_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>{safe_name}</b>\n<b><emoji document_id=5418376169055602355>ℹ️</emoji> Описание:</b> {safe_desc}\n<b><emoji document_id=5418299289141004396>🧑💻</emoji> Разработчик:</b> {dev_username}\n<emoji document_id=5411143117711624172>🪄</emoji> <code>{prefix}dlm {module_path}</code></blockquote>",
|
||||||
|
"command_template_ru": "<blockquote>{emoji} <code>{prefix}{command}</code> — {description}</blockquote>\n",
|
||||||
|
"inline_handler_template_ru": "{inline_bot} {command} — {description}\n",
|
||||||
|
"404_ru": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>Не найдено по запросу: <i>{query}</i></b></blockquote>",
|
||||||
|
"noargs_ru": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>Нет аргументов</b></blockquote>",
|
||||||
|
"?_ru": "<blockquote><emoji document_id=5951895176908640647>🔎</emoji> Запрос слишком короткий / не найден</blockquote>",
|
||||||
|
"no_info_ru": "<blockquote>Нет информации</blockquote>",
|
||||||
|
"inline404_ru": "<blockquote>Не найдено</blockquote>",
|
||||||
|
"inline?_ru": "<blockquote>Запрос слишком короткий / не найден</blockquote>",
|
||||||
|
"inlinenoargs_ru": "<blockquote>Введите запрос</blockquote>",
|
||||||
|
"history_ru": "<blockquote><emoji document_id=5879939498149679716>🔎</emoji> <b>История поиска:</b>\n{history}</blockquote>",
|
||||||
|
"filter_menu_ru": "Выберите фильтры",
|
||||||
|
"filter_cat_ru": "📑 Фильтр по категориям",
|
||||||
|
"apply_filters_ru": "✅ Применить фильтры",
|
||||||
|
"clear_filters_ru": "🗑 Очистить фильтры",
|
||||||
|
"back_to_results_ru": "🔙 Вернуться к результатам",
|
||||||
|
"empty_history_ru": "<blockquote><emoji document_id=5879939498149679716>🔎</emoji> <b>История поиска пуста!</b></blockquote>",
|
||||||
|
"enter_query_ru": "<blockquote>🔍 Введите новый поисковый запрос:</blockquote>",
|
||||||
|
"global_search_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> Глобальный поиск по <b>{query}</b> — найдено <b>{count}</b> модулей</blockquote>",
|
||||||
|
"change_query_ru": "🔍 Изменить запрос",
|
||||||
|
"no_modules_ru": "<blockquote>Модули недоступны.</blockquote>",
|
||||||
|
"filter_title_ru": "🏷 Фильтры",
|
||||||
|
"category_title_ru": "📂 Категории",
|
||||||
|
"selected_categories_ru": "<blockquote>✅ Выбранные категории: {categories}</blockquote>",
|
||||||
|
"no_categories_ru": "<blockquote>Категории не найдены в базе модулей</blockquote>",
|
||||||
|
"select_category_ru": "<blockquote>Выберите категории для запроса: <code>{query}</code>\n(Можно выбрать несколько)</blockquote>",
|
||||||
|
"back_ru": "🔙 Назад",
|
||||||
|
"category_ru": "📁 {category}",
|
||||||
|
"no_category_ru": "<blockquote>Без категории</blockquote>",
|
||||||
|
"global_button_ru": "🌍 Результаты",
|
||||||
|
"filtered_button_ru": "🏷️ Поиск с фильтрами",
|
||||||
|
"inline_search_ru": "🔍 Поиск в Limoka",
|
||||||
|
"inline_no_results_ru": "<blockquote>❌ Модули не найдены</blockquote>",
|
||||||
|
"inline_error_ru": "<blockquote>❌ Ошибка поиска</blockquote>",
|
||||||
|
"inline_short_query_ru": "<blockquote>❌ Запрос слишком короткий (мин. 2 символа)</blockquote>",
|
||||||
|
"inline_switch_pm_ru": "💬 Открыть в чате",
|
||||||
|
"inline_switch_pm_text_ru": "🔍 Результаты для: {query}",
|
||||||
|
"inline_start_message_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Limoka Поиск</b>\nВведите название модуля или ключевое слово</blockquote>",
|
||||||
|
"first_page_ru": "<blockquote>Это первая страница!</blockquote>",
|
||||||
|
"last_page_ru": "<blockquote>Это последняя страница!</blockquote>",
|
||||||
|
"display_error_ru": "<blockquote>Ошибка отображения модуля. Пожалуйста, попробуйте еще раз.</blockquote>",
|
||||||
|
"error_occurred_ru": "<blockquote>Произошла ошибка. Пожалуйста, попробуйте еще раз.</blockquote>",
|
||||||
|
"start_search_form_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Limoka Поиск</b>\nВведите ваш запрос для поиска модулей:</blockquote>",
|
||||||
|
"global_search_form_ru": "<blockquote><emoji document_id=5413334818047940135>🔍</emoji> <b>Глобальный Поиск</b>\nВведите запрос для поиска ВСЕХ модулей без фильтров:</blockquote>",
|
||||||
|
"history_cleared_ru": "<blockquote><emoji document_id=5427009710268689068>🧹</emoji> <b>История поиска очищена!</b></blockquote>",
|
||||||
|
"invalid_history_arg_ru": "<blockquote><emoji document_id=5210952531676504517>❌</emoji> <b>Неверный аргумент для команды истории. Используйте:</b>\n<code>.lshistory</code> - показать историю\n<code>.lshistory clear</code> - очистить историю</blockquote>",
|
||||||
|
"close_ru": "❌ Закрыть",
|
||||||
|
"watcher_no_tag_ru": "<blockquote>❌ Неверный формат сообщения. Тег #limoka не найден.</blockquote>",
|
||||||
|
"watcher_invalid_format_ru": "<blockquote>❌ Неверный формат. Ожидается: #limoka:path:signature</blockquote>",
|
||||||
|
"watcher_signature_invalid_ru": "<blockquote>❌ Неверная подпись! Установка отменена.</blockquote>",
|
||||||
|
"watcher_loader_missing_ru": "<blockquote>❌ Модуль загрузчика не найден.</blockquote>",
|
||||||
|
"watcher_module_not_found_ru": "<blockquote>❌ Модуль не найден в базе Limoka: <code>{path}</code></blockquote>",
|
||||||
|
"watcher_critical_ru": "<blockquote>❌ Критическая ошибка: {error}</blockquote>",
|
||||||
|
"indexing_in_progress_ru": "<blockquote>⚠️ База данных занята, попробуйте снова через несколько секунд. Если ошибка сохраняется, попробуйте удалить limoka_index в корневой папке юзербота. Если ошибка сохраняется снова, сообщите разработчикам</blockquote>",
|
||||||
|
"body_page_ru": "Команды"
|
||||||
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
@@ -44616,6 +44797,12 @@
|
|||||||
{
|
{
|
||||||
"sderepeat": "- ✋ Stop repeat | (RU) - ✋ Остановить повтор"
|
"sderepeat": "- ✋ Stop repeat | (RU) - ✋ Остановить повтор"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"sshuffle": "- 🔀 Enable shuffle | (RU) - 🔀 Включить перемешивание"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sdeshuffle": "- 🔀 Disable shuffle | (RU) - 🔀 Отключить перемешивание"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"snext": "- 👉 Next track | (RU) - 👉 Следующий трек"
|
"snext": "- 👉 Next track | (RU) - 👉 Следующий трек"
|
||||||
},
|
},
|
||||||
@@ -44656,7 +44843,10 @@
|
|||||||
"snowt": "| .snt - 🎧 Download current track. | (RU) | .snt - 🎧 Скачать играющий трек"
|
"snowt": "| .snt - 🎧 Download current track. | (RU) | .snt - 🎧 Скачать играющий трек"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ssearch": "| .sq - 🔍 Search for tracks. | (RU) | .sq - 🔍 Поиск треков."
|
"sq": "- 🔍 Search for tracks. | (RU) - 🔍 Поиск треков."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ssearch": "- 🔍 Search for tracks. | (RU) - 🔍 Поиск треков."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new_commands": [
|
"new_commands": [
|
||||||
@@ -44826,6 +45016,34 @@
|
|||||||
"is_inline_handler": false,
|
"is_inline_handler": false,
|
||||||
"decorators": []
|
"decorators": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "sshuffle",
|
||||||
|
"original_name": "sshufflecmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- 🔀 Enable shuffle",
|
||||||
|
"ru": "- 🔀 Включить перемешивание"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sdeshuffle",
|
||||||
|
"original_name": "sdeshufflecmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- 🔀 Disable shuffle",
|
||||||
|
"ru": "- 🔀 Отключить перемешивание"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "snext",
|
"name": "snext",
|
||||||
"original_name": "snextcmd",
|
"original_name": "snextcmd",
|
||||||
@@ -45008,12 +45226,26 @@
|
|||||||
"is_inline_handler": false,
|
"is_inline_handler": false,
|
||||||
"decorators": []
|
"decorators": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "sq",
|
||||||
|
"original_name": "sqcmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- 🔍 Search for tracks.",
|
||||||
|
"ru": "- 🔍 Поиск треков."
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "ssearch",
|
"name": "ssearch",
|
||||||
"original_name": "ssearchcmd",
|
"original_name": "ssearchcmd",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "| .sq - 🔍 Search for tracks.",
|
"default": "- 🔍 Search for tracks.",
|
||||||
"ru": "| .sq - 🔍 Поиск треков."
|
"ru": "- 🔍 Поиск треков."
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -45073,7 +45305,6 @@
|
|||||||
"no_devices_found": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>No devices found.</b>",
|
"no_devices_found": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>No devices found.</b>",
|
||||||
"device_changed": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playback transferred to {}.</b>",
|
"device_changed": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playback transferred to {}.</b>",
|
||||||
"autobio": "<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Spotify autobio {}</b>",
|
"autobio": "<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Spotify autobio {}</b>",
|
||||||
"no_ytdlp": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>yt-dlp not found... Check config or install yt-dlp (<code>{}terminal pip install yt-dlp</code>)</b>",
|
|
||||||
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Download failed</b>",
|
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Download failed</b>",
|
||||||
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Uploading banner...</i>",
|
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Uploading banner...</i>",
|
||||||
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Downloading track...</i>",
|
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Downloading track...</i>",
|
||||||
@@ -45087,6 +45318,8 @@
|
|||||||
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playlist {} deleted.</b>",
|
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playlist {} deleted.</b>",
|
||||||
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Please specify a playlist name.</b>",
|
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Please specify a playlist name.</b>",
|
||||||
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Select playback device:</b>",
|
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Select playback device:</b>",
|
||||||
|
"on-shuffle": "<tg-emoji emoji-id=5267246517701352801>🔀</tg-emoji> <b>Shuffle enabled.</b>",
|
||||||
|
"off-shuffle": "<tg-emoji emoji-id=5265105218806259720>🔀</tg-emoji> <b>Shuffle disabled.</b>",
|
||||||
"need_auth_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Выполни </b><code>.sauth</code><b> перед выполнением этого действия.</b>",
|
"need_auth_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Выполни </b><code>.sauth</code><b> перед выполнением этого действия.</b>",
|
||||||
"err_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Произошла ошибка.</b>\n<code>{}</code>",
|
"err_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Произошла ошибка.</b>\n<code>{}</code>",
|
||||||
"on-repeat_ru": "<tg-emoji emoji-id=5258420634785947640>🔄</tg-emoji> <b>Включен повтор трека.</b>",
|
"on-repeat_ru": "<tg-emoji emoji-id=5258420634785947640>🔄</tg-emoji> <b>Включен повтор трека.</b>",
|
||||||
@@ -45119,7 +45352,6 @@
|
|||||||
"no_devices_found_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Устройства не найдены.</b>",
|
"no_devices_found_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Устройства не найдены.</b>",
|
||||||
"device_changed_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Воспроизведение переключено на {}.</b>",
|
"device_changed_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Воспроизведение переключено на {}.</b>",
|
||||||
"autobio_ru": "<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Обновление био включено {}</b>",
|
"autobio_ru": "<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Обновление био включено {}</b>",
|
||||||
"no_ytdlp_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>yt-dlp не найден... Проверьте конфиг или установите yt-dlp (<code>{}terminal pip install yt-dlp</code>)</b>",
|
|
||||||
"snowt_failed_ru": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Ошибка скачивания.</b>",
|
"snowt_failed_ru": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Ошибка скачивания.</b>",
|
||||||
"uploading_banner_ru": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Загрузка баннера...</i>",
|
"uploading_banner_ru": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Загрузка баннера...</i>",
|
||||||
"downloading_track_ru": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Скачивание трека...</i>",
|
"downloading_track_ru": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Скачивание трека...</i>",
|
||||||
@@ -45132,7 +45364,9 @@
|
|||||||
"playlist_created_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} создан.</b>",
|
"playlist_created_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} создан.</b>",
|
||||||
"playlist_deleted_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} удален.</b>",
|
"playlist_deleted_ru": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} удален.</b>",
|
||||||
"no_playlist_name_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Пожалуйста, укажите название плейлиста.</b>",
|
"no_playlist_name_ru": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Пожалуйста, укажите название плейлиста.</b>",
|
||||||
"device_select_ru": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Выберите устройство для воспроизведения:</b>"
|
"device_select_ru": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Выберите устройство для воспроизведения:</b>",
|
||||||
|
"on-shuffle_ru": "<tg-emoji emoji-id=5267246517701352801>🔀</tg-emoji> <b>Перемешивание включено.</b>",
|
||||||
|
"off-shuffle_ru": "<tg-emoji emoji-id=5265105218806259720>🔀</tg-emoji> <b>Перемешивание отключено.</b>"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
@@ -79042,6 +79276,6 @@
|
|||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"total_modules": 998,
|
"total_modules": 998,
|
||||||
"generated_at": "2026-05-31T02:47:45.912076"
|
"generated_at": "2026-06-10T02:45:17.844204"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
# =======================================
|
# =======================================
|
||||||
#
|
#
|
||||||
# meta developer: @ke_mods
|
# meta developer: @ke_mods
|
||||||
# requires: telethon spotipy pillow requests yt-dlp curl_cffi
|
# requires: telethon spotipy pillow requests httpx
|
||||||
# scope: ffmpeg
|
# scope: ffmpeg
|
||||||
|
|
||||||
__version__ = (1, 0)
|
__version__ = (1, 0, 2)
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
@@ -35,6 +35,7 @@ import os
|
|||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import httpx
|
||||||
import requests
|
import requests
|
||||||
import spotipy
|
import spotipy
|
||||||
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps
|
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps
|
||||||
@@ -48,6 +49,14 @@ from .. import loader, utils
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logging.getLogger("spotipy").setLevel(logging.CRITICAL)
|
logging.getLogger("spotipy").setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Origin": "https://spotmate.online",
|
||||||
|
"Referer": "https://spotmate.online/en1",
|
||||||
|
}
|
||||||
|
|
||||||
class Banners:
|
class Banners:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -517,7 +526,6 @@ class SpotifyMod(loader.Module):
|
|||||||
"autobio": (
|
"autobio": (
|
||||||
"<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Spotify autobio {}</b>"
|
"<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Spotify autobio {}</b>"
|
||||||
),
|
),
|
||||||
"no_ytdlp": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>yt-dlp not found... Check config or install yt-dlp (<code>{}terminal pip install yt-dlp</code>)</b>",
|
|
||||||
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Download failed</b>",
|
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Download failed</b>",
|
||||||
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Uploading banner...</i>",
|
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Uploading banner...</i>",
|
||||||
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Downloading track...</i>",
|
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Downloading track...</i>",
|
||||||
@@ -531,6 +539,12 @@ class SpotifyMod(loader.Module):
|
|||||||
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playlist {} deleted.</b>",
|
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Playlist {} deleted.</b>",
|
||||||
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Please specify a playlist name.</b>",
|
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Please specify a playlist name.</b>",
|
||||||
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Select playback device:</b>",
|
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Select playback device:</b>",
|
||||||
|
"on-shuffle": (
|
||||||
|
"<tg-emoji emoji-id=5267246517701352801>🔀</tg-emoji> <b>Shuffle enabled.</b>"
|
||||||
|
),
|
||||||
|
"off-shuffle": (
|
||||||
|
"<tg-emoji emoji-id=5265105218806259720>🔀</tg-emoji> <b>Shuffle disabled.</b>"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
strings_ru = {
|
strings_ru = {
|
||||||
@@ -641,7 +655,6 @@ class SpotifyMod(loader.Module):
|
|||||||
"<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Обновление био"
|
"<tg-emoji emoji-id=6319076999105087378>🎧</tg-emoji> <b>Обновление био"
|
||||||
" включено {}</b>"
|
" включено {}</b>"
|
||||||
),
|
),
|
||||||
"no_ytdlp": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>yt-dlp не найден... Проверьте конфиг или установите yt-dlp (<code>{}terminal pip install yt-dlp</code>)</b>",
|
|
||||||
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Ошибка скачивания.</b>",
|
"snowt_failed": "\n\n<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Ошибка скачивания.</b>",
|
||||||
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Загрузка баннера...</i>",
|
"uploading_banner": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Загрузка баннера...</i>",
|
||||||
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Скачивание трека...</i>",
|
"downloading_track": "\n\n<tg-emoji emoji-id=5841359499146825803>🕔</tg-emoji> <i>Скачивание трека...</i>",
|
||||||
@@ -655,6 +668,12 @@ class SpotifyMod(loader.Module):
|
|||||||
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} удален.</b>",
|
"playlist_deleted": "<tg-emoji emoji-id=5776375003280838798>✅</tg-emoji> <b>Плейлист {} удален.</b>",
|
||||||
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Пожалуйста, укажите название плейлиста.</b>",
|
"no_playlist_name": "<tg-emoji emoji-id=5778527486270770928>❌</tg-emoji> <b>Пожалуйста, укажите название плейлиста.</b>",
|
||||||
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Выберите устройство для воспроизведения:</b>",
|
"device_select": "<tg-emoji emoji-id=5956561916573782596>📄</tg-emoji> <b>Выберите устройство для воспроизведения:</b>",
|
||||||
|
"on-shuffle": (
|
||||||
|
"<tg-emoji emoji-id=5267246517701352801>🔀</tg-emoji> <b>Перемешивание включено.</b>"
|
||||||
|
),
|
||||||
|
"off-shuffle": (
|
||||||
|
"<tg-emoji emoji-id=5265105218806259720>🔀</tg-emoji> <b>Перемешивание отключено.</b>"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -700,16 +719,10 @@ class SpotifyMod(loader.Module):
|
|||||||
lambda: "Template for Spotify AutoBio, supports {artist}, {title}",
|
lambda: "Template for Spotify AutoBio, supports {artist}, {title}",
|
||||||
),
|
),
|
||||||
loader.ConfigValue(
|
loader.ConfigValue(
|
||||||
"ytdlp_path",
|
"TimeOut",
|
||||||
"",
|
60,
|
||||||
"Path to ytdlp binary",
|
"Response timeout in seconds | Время ожидания ответа в секундах",
|
||||||
validator=loader.validators.String(),
|
validator=loader.validators.Integer(minimum=30),
|
||||||
),
|
|
||||||
loader.ConfigValue(
|
|
||||||
"cookies_path",
|
|
||||||
"",
|
|
||||||
"Path to your cookies for yt-dlp",
|
|
||||||
validator=loader.validators.String(),
|
|
||||||
),
|
),
|
||||||
loader.ConfigValue(
|
loader.ConfigValue(
|
||||||
"banner_version",
|
"banner_version",
|
||||||
@@ -944,36 +957,102 @@ class SpotifyMod(loader.Module):
|
|||||||
|
|
||||||
success = False
|
success = False
|
||||||
try:
|
try:
|
||||||
squery = query.replace('"', '').replace("'", "")
|
track_url = (query or "").strip().split("?")[0]
|
||||||
cookies = self.config["cookies_path"]
|
if "spotify:track:" in track_url:
|
||||||
ytdlp_flags = '-x --audio-format mp3 --audio-quality 0 --add-metadata --format "bestaudio/best" --no-playlist'
|
track_url = f"https://open.spotify.com/track/{track_url.split(':')[-1]}"
|
||||||
cookies_flag = f"--cookies {cookies} " if cookies else ""
|
|
||||||
cmd = (
|
|
||||||
f'{self.config["ytdlp_path"]} {ytdlp_flags} {cookies_flag}'
|
|
||||||
f'-o "{dl_dir}/%(title)s [%(id)s].%(ext)s" '
|
|
||||||
f'"ytsearch1:{squery}"'
|
|
||||||
)
|
|
||||||
|
|
||||||
proc = await asyncio.create_subprocess_shell(
|
if "track/" not in track_url:
|
||||||
cmd,
|
results = await asyncio.to_thread(
|
||||||
stdout=asyncio.subprocess.PIPE,
|
self.sp.search,
|
||||||
stderr=asyncio.subprocess.PIPE,
|
q=query,
|
||||||
)
|
limit=1,
|
||||||
_, stderr = await proc.communicate()
|
type="track",
|
||||||
|
)
|
||||||
|
items = (results or {}).get("tracks", {}).get("items", [])
|
||||||
|
if not items:
|
||||||
|
logger.error("SpotifyMod: Spotify track not found for %r", log_context or query)
|
||||||
|
await send_text(self.strings["snowt_failed"])
|
||||||
|
return False
|
||||||
|
|
||||||
if proc.returncode:
|
track_data = items[0]
|
||||||
err_text = stderr.decode(errors="ignore").strip() if stderr else "yt-dlp failed"
|
track_url = track_data.get("external_urls", {}).get("spotify") or f"https://open.spotify.com/track/{track_data['id']}"
|
||||||
logger.error("SpotifyMod: yt-dlp code %s for %r: %s", proc.returncode, log_context or query, err_text[-400:])
|
|
||||||
|
|
||||||
files = [f for f in os.listdir(dl_dir) if f.endswith(".mp3")]
|
async with httpx.AsyncClient(follow_redirects=True) as client:
|
||||||
if files:
|
csrf = await self.get_session(client)
|
||||||
success = await send_file(os.path.join(dl_dir, files[0]))
|
hdrs = {**headers, "X-CSRF-TOKEN": csrf}
|
||||||
|
|
||||||
|
info_res = await client.post(
|
||||||
|
"https://spotmate.online/getTrackData",
|
||||||
|
headers=hdrs,
|
||||||
|
json={"spotify_url": track_url},
|
||||||
|
timeout=self.config["TimeOut"],
|
||||||
|
)
|
||||||
|
info = info_res.json()
|
||||||
|
if info.get("type") != "track":
|
||||||
|
logger.error("SpotifyMod: spotmate returned no track for %r", log_context or query)
|
||||||
|
await send_text(self.strings["snowt_failed"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
track_id = info.get("id", track_url.split("/")[-1])
|
||||||
|
conv_res = await client.post(
|
||||||
|
"https://spotmate.online/convert",
|
||||||
|
headers=hdrs,
|
||||||
|
json={"urls": track_url},
|
||||||
|
timeout=self.config["TimeOut"],
|
||||||
|
)
|
||||||
|
conv = conv_res.json()
|
||||||
|
download_url = conv.get("url") or conv.get("download_url")
|
||||||
|
task_id = conv.get("task_id") or conv.get("taskId")
|
||||||
|
|
||||||
|
if not download_url and task_id:
|
||||||
|
for _ in range(40):
|
||||||
|
await asyncio.sleep(4.5)
|
||||||
|
task_res = await client.get(
|
||||||
|
f"https://spotmate.online/tasks/{task_id}",
|
||||||
|
headers={**hdrs, "Accept": "application/json"},
|
||||||
|
timeout=self.config["TimeOut"],
|
||||||
|
)
|
||||||
|
task = task_res.json()
|
||||||
|
if task.get("error"):
|
||||||
|
logger.error("SpotifyMod: task error for %r", log_context or query)
|
||||||
|
await send_text(self.strings["dl_err"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
data = task.get("data") or task.get("result") or {}
|
||||||
|
status = str(data.get("status") or data.get("state") or "").lower()
|
||||||
|
if status == "finished":
|
||||||
|
download_url = (
|
||||||
|
data.get("url")
|
||||||
|
or data.get("download_url")
|
||||||
|
or (data.get("result") or {}).get("url")
|
||||||
|
or (data.get("result") or {}).get("download_url")
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
if status in ("failed", "error", "expired", "cancelled"):
|
||||||
|
logger.error("SpotifyMod: task failed for %r", log_context or query)
|
||||||
|
await send_text(self.strings["dl_err"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not download_url:
|
||||||
|
logger.error("SpotifyMod: download timeout for %r", log_context or query)
|
||||||
|
await send_text(self.strings["snowt_failed"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
file_res = await client.get(
|
||||||
|
download_url,
|
||||||
|
headers={"User-Agent": headers["User-Agent"], "Referer": "https://spotmate.online/en1"},
|
||||||
|
timeout=self.config["TimeOut"],
|
||||||
|
)
|
||||||
|
|
||||||
|
file_path = os.path.join(dl_dir, f"{track_id}.mp3")
|
||||||
|
with open(file_path, "wb") as f:
|
||||||
|
f.write(file_res.content)
|
||||||
|
|
||||||
|
success = await send_file(file_path)
|
||||||
if not success:
|
if not success:
|
||||||
logger.error("SpotifyMod: failed to send %r (target=%s)", log_context or query, type(target).__name__)
|
logger.error("SpotifyMod: failed to send %r (target=%s)", log_context or query, type(target).__name__)
|
||||||
await send_text(self.strings["dl_err"])
|
await send_text(self.strings["dl_err"])
|
||||||
else:
|
|
||||||
logger.error("SpotifyMod: yt-dlp produced no mp3 for %r", log_context or query)
|
|
||||||
await send_text(self.strings["snowt_failed"])
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Download track error (%s): %s", log_context or "no context", e, exc_info=True)
|
logger.error("Download track error (%s): %s", log_context or "no context", e, exc_info=True)
|
||||||
@@ -986,6 +1065,20 @@ class SpotifyMod(loader.Module):
|
|||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
async def get_session(self, client: httpx.AsyncClient) -> str:
|
||||||
|
res = await client.get(
|
||||||
|
"https://spotmate.online/en1",
|
||||||
|
headers={
|
||||||
|
"User-Agent": headers["User-Agent"],
|
||||||
|
"Accept": "text/html",
|
||||||
|
},
|
||||||
|
timeout=self.config["TimeOut"],
|
||||||
|
)
|
||||||
|
match = re.search(r'csrf-token[^>]*content="([^"]+)"', res.text)
|
||||||
|
if not match:
|
||||||
|
raise ValueError("CSRF token not found")
|
||||||
|
return match.group(1)
|
||||||
|
|
||||||
def _short_text(self, text: str, limit: int = 60) -> str:
|
def _short_text(self, text: str, limit: int = 60) -> str:
|
||||||
text = " ".join(text.split())
|
text = " ".join(text.split())
|
||||||
if len(text) <= limit:
|
if len(text) <= limit:
|
||||||
@@ -1126,7 +1219,13 @@ class SpotifyMod(loader.Module):
|
|||||||
|
|
||||||
tracks = results["tracks"]["items"]
|
tracks = results["tracks"]["items"]
|
||||||
store_id = id(tracks)
|
store_id = id(tracks)
|
||||||
self._sp_store[store_id] = [(t.get("name", "Unknown"), ", ".join(a.get("name", "") for a in t.get("artists", []) if a.get("name")) or "Unknown Artist") for t in tracks]
|
self._sp_store[store_id] = [
|
||||||
|
(
|
||||||
|
t.get("name", "Unknown"),
|
||||||
|
", ".join(a.get("name", "") for a in t.get("artists", []) if a.get("name")) or "Unknown Artist",
|
||||||
|
)
|
||||||
|
for t in tracks
|
||||||
|
]
|
||||||
|
|
||||||
entries = []
|
entries = []
|
||||||
for i, track in enumerate(tracks):
|
for i, track in enumerate(tracks):
|
||||||
@@ -1427,6 +1526,26 @@ class SpotifyMod(loader.Module):
|
|||||||
self.sp.repeat("context")
|
self.sp.repeat("context")
|
||||||
await utils.answer(message, self.strings["off-repeat"])
|
await utils.answer(message, self.strings["off-repeat"])
|
||||||
|
|
||||||
|
@error_handler
|
||||||
|
@tokenized
|
||||||
|
@loader.command(
|
||||||
|
ru_doc="- 🔀 Включить перемешивание"
|
||||||
|
)
|
||||||
|
async def sshufflecmd(self, message: Message):
|
||||||
|
"""- 🔀 Enable shuffle"""
|
||||||
|
self.sp.shuffle(True)
|
||||||
|
await utils.answer(message, self.strings["on-shuffle"])
|
||||||
|
|
||||||
|
@error_handler
|
||||||
|
@tokenized
|
||||||
|
@loader.command(
|
||||||
|
ru_doc="- 🔀 Отключить перемешивание"
|
||||||
|
)
|
||||||
|
async def sdeshufflecmd(self, message: Message):
|
||||||
|
"""- 🔀 Disable shuffle"""
|
||||||
|
self.sp.shuffle(False)
|
||||||
|
await utils.answer(message, self.strings["off-shuffle"])
|
||||||
|
|
||||||
@error_handler
|
@error_handler
|
||||||
@tokenized
|
@tokenized
|
||||||
@loader.command(
|
@loader.command(
|
||||||
@@ -1730,11 +1849,10 @@ class SpotifyMod(loader.Module):
|
|||||||
@error_handler
|
@error_handler
|
||||||
@tokenized
|
@tokenized
|
||||||
@loader.command(
|
@loader.command(
|
||||||
ru_doc="| .sq - 🔍 Поиск треков.",
|
ru_doc="- 🔍 Поиск треков."
|
||||||
alias="sq"
|
|
||||||
)
|
)
|
||||||
async def ssearchcmd(self, message: Message):
|
async def sqcmd(self, message: Message):
|
||||||
"""| .sq - 🔍 Search for tracks."""
|
"""- 🔍 Search for tracks."""
|
||||||
args = utils.get_args_raw(message)
|
args = utils.get_args_raw(message)
|
||||||
if not args:
|
if not args:
|
||||||
await utils.answer(message, self.strings["no_search_query"])
|
await utils.answer(message, self.strings["no_search_query"])
|
||||||
@@ -1800,6 +1918,13 @@ class SpotifyMod(loader.Module):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@error_handler
|
||||||
|
@tokenized
|
||||||
|
@loader.command(ru_doc="- 🔍 Поиск треков.")
|
||||||
|
async def ssearchcmd(self, message: Message):
|
||||||
|
"""- 🔍 Search for tracks."""
|
||||||
|
await self.sqcmd(message)
|
||||||
|
|
||||||
async def watcher(self, message: Message):
|
async def watcher(self, message: Message):
|
||||||
"""Watcher is used to update token"""
|
"""Watcher is used to update token"""
|
||||||
if not self.sp:
|
if not self.sp:
|
||||||
@@ -1856,3 +1981,4 @@ class SpotifyMod(loader.Module):
|
|||||||
await refresh_token.delete()
|
await refresh_token.delete()
|
||||||
else:
|
else:
|
||||||
self.set("NextRefresh", time.time() + 300)
|
self.set("NextRefresh", time.time() + 300)
|
||||||
|
# слендермен
|
||||||
|
|||||||
Reference in New Issue
Block a user