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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

msoc-0.3.1.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

msoc-0.3.1-py3-none-any.whl (26.3 kB view details)

Uploaded Python 3

File details

Details for the file msoc-0.3.1.tar.gz.

File metadata

  • Download URL: msoc-0.3.1.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for msoc-0.3.1.tar.gz
Algorithm Hash digest
SHA256 9bb9d4d4b1c803d103e12bf3d8019e32a4b4ffc2457abffbf775d3e54c8ed34a
MD5 b9bbe7585ef1bafe3b354b41262627a1
BLAKE2b-256 a844c37fbb57fc1753e2641b94a521f4dec0fa012d1b46982687395b7aecb1eb

See more details on using hashes here.

File details

Details for the file msoc-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: msoc-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 26.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for msoc-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fbb8ff186bd3f2efadb4d511927f3f1fd95c6451503c8732c38eac45fe9746d8
MD5 fc0c325fbcf12a123f0d9d98201a712c
BLAKE2b-256 850509d1e70f76d13ac60da72633efd86877984c39b2ecc464d0837b798f2d0b

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page