Сканирование архива аудиофайлов и запись метаданных

Источник: AudD•

Сканирование архива аудиофайлов и запись метаданных

Обход каталога аудиофайлов, идентификация каждого из них с помощью AudD и запись исполнителя, названия, альбома и ISRC в возобновляемый CSV-файл.

Этот рецепт обходит каталог с аудиофайлами, идентифицирует каждый из них с помощью AudD и записывает результаты (исполнитель, название, альбом, ISRC и многое другое) в CSV-файл с одной строкой на файл. Он предназначен для всех, у кого есть неразобранный архив: папка с рипами в стиле track01.mp3, полевые записи, старая фонотека с поврежденными тегами или набор файлов, которые нужно сопоставить с их реальным содержимым.

Скрипт создан для работы с тысячами файлов в реальных условиях: он обрабатывает файлы параллельно с ограниченным пулом воркеров, бережно относится к лимитам частоты запросов, пропускает файлы, уже записанные в CSV, что позволяет останавливать и возобновлять процесс, а также фиксирует файлы без совпадений и нечитаемые файлы явно, вместо того чтобы молча их отбрасывать.

Что вы создадите

Один Python-скрипт scan_archive.py, который вы запускаете для определенной директории. Он:

  • Обходит директорию в поисках аудиофайлов.
  • Загружает существующий CSV и пропускает уже обработанные файлы (возможность возобновления).
  • Распознает каждый оставшийся файл с помощью ограниченного пула потоков.
  • Записывает одну строку в CSV для каждого файла по мере поступления результатов (matched, no_match или error), поэтому сбой никогда не приведет к потере уже выполненной работы.

Для коротких фрагментов скрипт использует стандартную конечную точку (POST https://api.audd.io/), которая возвращает одно совпадение менее чем за 2 секунды. Для длинных файлов — треков полной длины, миксов, подкастов — вы переключаетесь на корпоративную конечную точку (enterprise endpoint), которая разбивает файл на чанки на стороне сервера и возвращает каждый трек; в рецепте показаны оба варианта и объясняется, когда переключаться.

Установите лимит для каждого корпоративного вызова. Корпоративная конечная точка тарифицируется за каждые 12 секунд обработанного аудио. В масштабах всего архива вызов без ограничений может обрабатывать часы аудио на один файл. Удерживайте лимит и увеличивайте его только тогда, когда вы знаете стоимость для ваших входных данных.

Установите лимит для каждого корпоративного вызова. Корпоративная конечная точка тарифицируется за каждые 12 секунд обработанного аудио. В масштабах всего архива вызов без ограничений может обрабатывать часы аудио на один файл. Удерживайте лимит и увеличивайте его только тогда, когда вы знаете стоимость для ваших входных данных.

Разовое сканирование не требует написания кода. CLI-утилита AudD записывает результаты папки в CSV, возобновляет прерванный запуск и пропускает файлы, которые она уже идентифицировала: audd recognize ./archive --max-files 500 --format csv > archive.csv. Создавайте скрипт ниже, когда сканирование является частью вашего собственного пайплайна.

Разовое сканирование не требует написания кода. CLI-утилита AudD записывает результаты папки в CSV, возобновляет прерванный запуск и пропускает файлы, которые она уже идентифицировала: audd recognize ./archive --max-files 500 --format csv > archive.csv. Создавайте скрипт ниже, когда сканирование является частью вашего собственного пайплайна.

Предварительные требования

  • API-токен с сайта dashboard.audd.io. Для получения ISRC и UPC в ответах требуется план Startup или выше; стандартная конечная точка возвращает основные теги на любом плане.
  • Python 3.10+ с официальным SDK: pip install audd
  • Директория с аудиофайлами. Поддерживаемые аудиоформаты: MP3, WAV, FLAC, M4A, OGG, AAC, WMA, AIFF.

Пошаговое руководство

Шаг 1: Распознавание одного локального файла

Начните с наименьшей единицы: идентифицируйте один файл на диске и выведите теги. SDK принимает путь напрямую. (audd.tech/example.mp3 — это известный трек, если вы хотите проверить путь, прежде чем указывать на свои собственные файлы.)

recognize возвращает RecognitionResult при совпадении и None при успешном вызове без совпадений — именно это различие является причиной наличия в CSV статусов как no_match, так и error. Значение None не является ошибкой; это четкое «мы не знаем этот файл».

Шаг 2: Обход директории

Соберите файлы для обработки. Выполняйте сопоставление по расширению, чтобы случайно не передать в SDK обложку в формате JPEG или файл .cue.

rglob("*") рекурсивно обходит поддиректории; переключитесь на glob("*"), если вам нужен только верхний уровень.

Шаг 3: Обеспечение возможности возобновления

Перед началом сканирования прочитайте CSV-файл, в который вы пишете, и запомните, какие файлы уже обработаны. При перезапуске они будут пропущены. Ключом является абсолютный путь к файлу.

Поскольку каждый файл получает строку (включая no_match и error), возобновленный процесс не будет повторно пытаться обработать файлы, которые уже не удалось декодировать. Если вы хотите повторить попытку для ошибок при следующем запуске, отфильтруйте already_done только по тем строкам, где status == "matched" или status == "no_match".

Шаг 4: Распознавание одного файла в строку таблицы

Оберните процедуру распознавания одного файла так, чтобы она всегда возвращала строку CSV, что бы ни случилось — совпадение, отсутствие совпадения или нечитаемый/недоступный файл. Это единица работы, которую выполняет пул воркеров.

Передача дескриптора открытого файла (rb) позволяет SDK повторно открыть его при попытке повтора. Файл, который не удается декодировать как аудио, вызывает исключение AudDInvalidAudioError, которое превращается в строку ошибки вместо прерывания процесса. OSError отслеживает файлы, которые исчезли или имеют проблемы с правами доступа.

Шаг 5: Запуск ограниченного пула воркеров и потоковая запись строк в CSV

Распознавание зависит от операций ввода-вывода (вы ждете ответа сети), поэтому пул потоков обеспечивает реальное параллельное выполнение. Ограничьте его. Небольшой пул позволяет соблюдать лимиты API и удерживать потребление памяти на стабильном уровне при работе с большим архивом. Записывайте каждую строку по мере поступления результата, чтобы при прерывании работы все уже выполненное сохранилось.

Запуск:

Вы увидите по одной строке на каждый завершенный файл — matched, no_match или error — и файл results.csv, который растет строка за строкой. Остановите процесс с помощью Ctrl-C и перезапустите ту же команду; она продолжится с того места, где остановилась, поскольку завершенные пути уже есть в CSV.

Шаг 6: Обработка длинных файлов с помощью корпоративной конечной точки

Стандартная конечная точка предназначена для коротких клипов и имеет ограничение на размер файла в 10 МБ. Для треков полной длины, миксов или подкастов — всего длинного или превышающего 10 МБ — используйте корпоративную конечную точку (enterprise endpoint). Она разбивает файл на чанки на стороне сервера и возвращает каждый совпавший трек, поэтому один входной файл может породить несколько строк. Замените вызов распознавания в scan_one:

Когда файл может порождать множество строк, записывайте список и настраивайте логику возобновления по ключу пути (любая строка с этим путем означает, что файл обработан). Для архива длинных файлов, где вам нужно лишь подтвердить, содержит ли файл известную музыку, а не получить полный треклист, добавьте every=5 для распознавания каждого пятого чанка и низкий лимит для ранней остановки — это значительно сократит объем тарифицируемого аудио.

Что вы получаете на выходе

CSV с одной строкой на файл (или на одно совпадение для длинных файлов в enterprise-режиме):

no_match означает, что AudD обработала файл и ничего не распознала — это нормально для голосовых заметок, фоновых записей или малоизвестных материалов, отсутствующих в базе данных из 160 миллионов треков. Это не то же самое, что error, которая означает, что файл не удалось прочитать или вызов API завершился ошибкой.

Обработка ошибок

Скрипт уже направляет каждую ошибку отдельного файла в строку ошибки. Ошибки, требующие внимания на уровне всего процесса, а не отдельного файла:

  • Ошибки аутентификации (AudDAuthenticationError) — неверный или отсутствующий токен. Это приводит к сбою для каждого файла, поэтому перехватывайте ошибку один раз при запуске, вместо того чтобы записывать тысячи идентичных строк с ошибками.
  • Ошибки квот / лимита запросов (AudDQuotaError, AudDRateLimitError) — вы исчерпали лимит запросов или частоту их отправки. Уменьшите MAX_WORKERS, увеличите THROTTLE_SECONDS и перезапустите скрипт; благодаря возможности возобновления вы повторите попытку только для того, что не успело завершиться.
  • Ошибки недействительного аудио (AudDInvalidAudioError) — один нечитаемый файл. Записывается как строка ошибки, процесс продолжается.
  • Ошибки соединения (AudDConnectionError) — временные сетевые проблемы. SDK автоматически повторяет попытки при сбоях сети до загрузки; постоянная ошибка попадает в колонку ошибок для этого файла.

Чтобы остановить выполнение целиком, когда токен явно неверен, поднимите проверку аутентификации выше пула:

Дальнейшие шаги

  • Запись тегов обратно в файлы. Как только файл results.csv станет корректным, второй проход с mutagen позволит записать исполнителя, название и альбом в метаданные каждого файла. Разделяйте распознавание и тегирование, чтобы вы могли проверить CSV перед изменением файлов.
  • Добавление ссылок на стриминговые сервисы. Передайте return_metadata=["apple_music", "spotify"] в функцию распознавания, чтобы заполнить блоки провайдеров и добавить столбцы с прямыми URL-адресами сервисов. Каждый провайдер добавляет задержку, поэтому запрашивайте только то, что будете сохранять.
  • Чтение полей за пределами типизированной структуры. Любое поле сервера, которое SDK не предоставляет в виде типизированного свойства, доступно в карте model_extra результата (модели Python SDK построены на базе Pydantic) — добавьте его в качестве столбца CSV, если это необходимо.
  • Сравнение с вашим собственным каталогом. Чтобы идентифицировать файлы по принадлежащим вам трекам, а не по публичной базе данных (проверка на утечки, поиск повторного использования семплов), сначала загрузите свои треки в пользовательский каталог — свяжитесь с [email protected] для получения доступа.
  • Создание сканера авторских прав для контента, загружаемого пользователями
  • Создание бота для Discord, который определяет песни в голосовых каналах
  • Документация по Python SDK
  • Справочник по API

О чём эта статья