Skip to main content

🎵 MSOC - Библиотека для быстрого и асинхронного поиска музыки

Python License PyPI Downloads

✨ Особенности

  • ⚡ Асинхронный поиск музыки
  • 🔍 Поддержка нескольких источников
  • 🛠️ Простое расширение новыми движками
  • 📦 Легкая интеграция в проекты
  • 🚀 Быстрая установка через pip
  • 🖥️ TUI (Terminal User Interface) с поиском, прослушиванием и скачиванием

📦 Установка

Для установки библиотеки можно использовать pip:

pip install msoc

Так же можно установить из исходников:

git clone https://github.com/paranoik1/msoc.git

cd MSOC

pip install .

🚀 Использование

🖥️ TUI (Textual User Interface)

Запустите TUI для интерактивного поиска, прослушивания и скачивания музыки:

msoc --tui
# or
python -m msoc --tui

alt text

TUI позволяет:

  • Искать треки по запросу
  • Прослушивать треки через ffmpeg (автоопределение PulseAudio/PipeWire)
  • Скачивать треки в текущую директорию
  • Видеть продолжительность треков

Требование: для работы TUI нужен ffmpeg в системе. При разработке использовался ffmpeg version n8.1.2.

Эксперименты с оптимизацией

В процессе разработки я экспериментировал с тем, как уменьшить количество сетевых запросов при проигрывании. Для тестов использовал wondershaper — под Linuх он позволяет искусственно резать пропускную способность интерфейса, что удобно симулировать слабый интернет.

Сейчас воспроизведение выглядит так:

  1. ffmpeg скачивает трек во временную папку (-c:a copy — без перекодирования, просто сохраняет поток как есть).
    • Для получения некоторых данных об аудио файле раньше использовался ffprobe по url аудио, что было удобно, однако присутствовала неприятная задержка. Этот метод был заменен чтением stderr ffmpeg процесса, который скачивает файл. Таким образом удается избежать дополнительной задержки
  2. Второй ffmpeg читает уже локальный файл, декодирует в PCM и отправляет в sounddevice.

Загрузка и воспроизведение работают в разных потоках, поэтому не блокируют друг друга — можно начать слушать, не дожидаясь полной загрузки.

Как работает скачивание

Когда пользователь нажимает Download, логика такая:

  • Если трек уже загружен во временную папку (докачался во время прослушивания) — просто копируем оттуда в текущую директорию. Никаких новых запросов в сеть.
  • Если трек прямо сейчас играет, но ещё не докачался — ждём, пока фоновый ffmpeg закончит, и копируем. Пользователь видит ... на кнопке.
  • Если трек не играл и не загружался — ffmpeg скачивает напрямую (-c:a copy), сохраняя в текущую папку.

💻 В консоле

usage: msoc [-h] [--tui] [--mode {fast,full}] [query]

Быстрый асинхронный поиск музыки

positional arguments:
  query               Поисковый запрос

options:
  -h, --help          show this help message and exit
  --tui               Запустить графический интерфейс (TUI)
  --mode {fast,full}  Режим поиска: fast (только первые
                      страницы) или full (все страницы)

При запуске будет выведена информация о найденных треках: Name, Artist, URL, Engine (название движка) и Meta (дополнительные метаданные).

⌨️ В коде

Импортируйте модуль msoc и используйте функцию search() для поиска музыки:

from msoc import search
import asyncio


async def main():
    query = input("Запрос: ")

    async for sound in search(query):
        print(f"Name: {sound.title}\nArtist: {sound.artist}\nURL: {sound.url}")
        print("================================================")


asyncio.run(main())

Функция search() принимает поисковый запрос и опциональный параметр mode (по умолчанию SearchMode.Fast):

  • SearchMode.Fast — каждый движок выполняет только первый запрос (одна страница результатов).
  • SearchMode.Full — движок пытается собрать все страницы результатов через функцию search_full. Если движок не реализует search_full, используется обычный search с предупреждением.
from msoc import search, SearchMode

async for sound in search("query", mode=SearchMode.Full):
    ...

🎶 Класс Sound

Класс Sound содержит информацию о песне.

Поле Тип Описание
title str Название песни
url str Ссылка на скачивание
artist str | None Исполнитель (опционально)
meta dict[str, Any] Дополнительные метаданные (по умолчанию {})
_engine str | None Движок-источник, заполняется автоматически

🔌 Реализованные движки поиска

В настоящее время библиотека MSOC поддерживает следующие движки поиска:

Движки загружаются автоматически при импорте пакета msoc.

❌ Exceptions

Библиотека MSOC определяет следующие исключения:

  • LoadedEngineNotFoundError: Выбрасывается, когда движок поиска не был найден в загруженных движках.

🛠️ Создание своих поисковых движков

Для создания собственных поисковых движков на Python вы можете использовать следующий подход:

  1. Создайте новый Python-файл для вашего поискового движка:

    • Например, создайте файл my_search_engine.py.
  2. Определите асинхронную функцию search(query), которая будет реализовывать поисковый алгоритм:

    • Реализуйте логику поиска, взаимодействуя с API или веб-страницами источников, которые вы хотите использовать.
    • Можете использовать библиотеки, такие как aiohttp, beautifulsoup4 и другие, для выполнения HTTP-запросов и парсинга HTML-страниц.

Для поддержки режима Mode.Full движок может реализовать функцию search_full(query) с той же сигнатурой, что и search. Она должна проходить по всем страницам результатов. Если search_full не определена, Mode.Full просто использует search (одна страница).

Функция search внутри движка должна возвращать генератор объектов Sound.
Пример реализации функции search(query) в my_search_engine.py:

import aiohttp
from bs4 import BeautifulSoup

from msoc.sound import Sound


async def search(query: str):
    async with aiohttp.ClientSession() as session:
        async with session.get(f"https://example.com/search?q={query}") as response:
            html = await response.text()

    soup = BeautifulSoup(html, "html.parser")

    for item in soup.find_all("div", class_="search-result"):
        name = item.find("h3").get_text(strip=True)
        artist = item.find("span", class_="artist").get_text(strip=True)
        url = item.find("a").get("href")
        yield Sound(name, url, artist)
  1. Подключите ваш поисковый движок к системе:
from msoc import register_engine, get_engines

import my_search_engine


register_engine("my_search_engine", my_search_engine)
print(get_engines())
  • Замените my_search_engine на название вашего python файла.
  • Далее вызываем get_engines(), чтобы удостовериться, что движок был успешно загружен
  1. Теперь при запуске основной search функции, ваш движок будет автоматически загружен и использован для поиска песен

ℹ️ P.S 1

Если вам нужно подключить поисковой движок, файл которого находится не в текущей папке проекта, можете воспользоваться встроенным python пакетом importlib

from msoc import register_engine
from importlib import util

spec = util.spec_from_file_location("my_search_engine", "/path/to/python/file/my_search_engine.py")
module = util.module_from_spec(spec)

spec.loader.exec_module(module)


register_engine("my_search_engine", module)

ℹ️ P.S 2

Если вам не нужен какой либо поисковой движок, используй unload_search_engine для его удаления из загруженных:

from msoc import unload_search_engine, engines

unload_search_engine("my_search_engine")
print(engines())

ℹ️ P.S 3 — Проверка доступности сервиса

Проверка доступности теперь лежит на самом движке. Если сайт недоступен, движок должен сам обработать ошибку в search() (логирование, возврат пустого результата и т.д.). msoc не делает отдельного запроса для проверки — лишний сетевой вызов только замедляет поиск. Переменная URL в модуле движка теперь используется только как константа внутри самого движка.

🤝 Contribution

Если вы хотите внести свой вклад в развитие библиотеки MSOC, вы можете:

  • 🐞 Сообщить об ошибках или предложить новые функции
  • 🎛️ Разработать и добавить новые движки поиска
  • 📖 Улучшить документацию
  • 🔧 Исправить существующие проблемы

Open Issues Stars

Metadata

Release files for msoc 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for msoc 0.3.1
File Size Uploaded
msoc-0.3.1.tar.gz 24.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for msoc 0.3.1
File Interpreter ABI Platform
msoc-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 50.9 kB

Release files / msoc-0.3.1.tar.gz

Download URL msoc-0.3.1.tar.gz
Size 24.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9bb9d4d4b1c803d103e12bf3d8019e32a4b4ffc2457abffbf775d3e54c8ed34a
BLAKE2b-256 checksum
How to use checksums
a844c37fbb57fc1753e2641b94a521f4dec0fa012d1b46982687395b7aecb1eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.25

Release files / msoc-0.3.1-py3-none-any.whl

Download URL msoc-0.3.1-py3-none-any.whl
Size 26.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fbb8ff186bd3f2efadb4d511927f3f1fd95c6451503c8732c38eac45fe9746d8
BLAKE2b-256 checksum
How to use checksums
850509d1e70f76d13ac60da72633efd86877984c39b2ecc464d0837b798f2d0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.25

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page