Розробка платформи стримінгу музики

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка платформи стримінгу музики
Складна
від 2 тижнів до 3 місяців
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка платформи стриминга музики

Стриминг музики — це не просто «віддати mp3 через HTTP». Платформа, яка повинна витримувати навантаження, забезпечувати low-latency відтворення, керувати правами та монетизацією — інженерна задача з десятком нетривіальних вузлів. Нижче — архітектура та реалізація з реальними компромісами.

Протоколи доставки аудіо

Три варіанти, кожен під свою задачу.

Progressive download (псевдостриминг) — найпростіший. Файл віддається через звичайний HTTP з підтримкою Range-запитів. Браузер буферизує та відтворює. Підходить для невеликих бібліотек без суворих обмежень на скачування.

location /audio/ {
    root /var/media;
    add_header Accept-Ranges bytes;
    add_header Cache-Control "no-store"; # для DRM
    # X-Accel-Redirect якщо файли за авторизацією
}

HLS (HTTP Live Streaming) — стандарт для продакшну. Файл нарізається на сегменти по 5–10 секунд, клієнт підгружає по манівфесту. Дозволяє адаптивний бітрейт (ABR): клієнт переключається між 128/256/320 kbps залежно від каналу.

# FFmpeg: нарізка в HLS з трьома якостями
ffmpeg -i input.flac \
  -filter_complex "[0:a]asplit=3[a1][a2][a3]" \
  -map "[a1]" -codec:a aac -b:a 128k -vn \
    -hls_time 6 -hls_list_size 0 \
    -hls_segment_filename "out/128k_%03d.aac" out/128k.m3u8 \
  -map "[a2]" -codec:a aac -b:a 256k -vn \
    -hls_time 6 -hls_list_size 0 \
    -hls_segment_filename "out/256k_%03d.aac" out/256k.m3u8 \
  -map "[a3]" -codec:a aac -b:a 320k -vn \
    -hls_time 6 -hls_list_size 0 \
    -hls_segment_filename "out/320k_%03d.aac" out/320k.m3u8

Манівфест верхнього рівня (master.m3u8) перелічує варіанти, клієнт вибирає сам.

MPEG-DASH — альтернатива HLS, краще підтримує DRM через EME (Encrypted Media Extensions). Якщо потрібна захист контенту рівня лейблів — DASH + Widevine/FairPlay.

Архітектура обробки контенту

Загрузка треку — це пайплайн, а не просто зберігання файла.

Upload → Validation → Transcoding → Waveform → Fingerprint → CDN → DB
# Celery task: повний пайплайн обробки
from celery import chain

@app.task
def process_upload(track_id: int, raw_path: str):
    pipeline = chain(
        validate_audio.s(track_id, raw_path),
        transcode_variants.s(),       # 128/256/320 + HLS segments
        generate_waveform.s(),        # peaks.json для візуалізації
        fingerprint_audio.s(),        # AcoustID / Chromaprint
        push_to_cdn.s(),
        update_track_status.s('ready')
    )
    pipeline.delay()

@app.task
def transcode_variants(track_id: int, validated_path: str):
    qualities = [
        ('128k', '128k', 'aac'),
        ('256k', '256k', 'aac'),
        ('320k', '320k', 'mp3'),   # для офлайн-скачування
        ('lossless', None, 'flac'), # для hi-fi тиру
    ]
    results = []
    for name, bitrate, codec in qualities:
        out = transcode(validated_path, bitrate, codec)
        segment_hls(out, name, track_id)
        results.append((name, out))
    return track_id, results

Генерація волнової форми

Waveform — стандартний UI елемент. Бібліотека audiowaveform від BBC:

audiowaveform -i track.mp3 -o peaks.json \
  --pixels-per-second 10 \
  --bits 8
# peaks.json: { "bits": 8, "length": 1234, "data": [-12, 15, -8, 22, ...] }

На фронтенді — WaveSurfer.js або кастомний Canvas-рендер.

Система прав та ліцензування

Без управління правами платформу не запустити легально. Мінімальна модель:

CREATE TABLE tracks (
  id           BIGSERIAL PRIMARY KEY,
  title        TEXT NOT NULL,
  duration_sec INT,
  isrc         CHAR(12),          -- International Standard Recording Code
  status       TEXT DEFAULT 'processing'
);

CREATE TABLE track_rights (
  track_id     BIGINT REFERENCES tracks(id),
  territory    CHAR(2),           -- ISO 3166-1 alpha-2, NULL = worldwide
  right_type   TEXT,              -- 'stream', 'download', 'sync'
  holder_id    BIGINT,
  expires_at   TIMESTAMPTZ,
  PRIMARY KEY (track_id, territory, right_type)
);

-- Перевірка права перед виданням URL
CREATE OR REPLACE FUNCTION can_stream(p_track_id BIGINT, p_territory CHAR(2))
RETURNS BOOLEAN AS $$
  SELECT EXISTS (
    SELECT 1 FROM track_rights
    WHERE track_id = p_track_id
      AND right_type = 'stream'
      AND (territory IS NULL OR territory = p_territory)
      AND (expires_at IS NULL OR expires_at > NOW())
  );
$$ LANGUAGE sql STABLE;

Signed URLs та захист стрімів

Прямі посилання на файли віддавати нельзя — їх зберегти і поширять. Підписані URL з коротким TTL:

// Laravel: генерація підписаного URL через CDN (Cloudflare / AWS CloudFront)
class StreamController extends Controller
{
    public function stream(Request $request, int $trackId): JsonResponse
    {
        $track = Track::findOrFail($trackId);

        // Перевіримо територію за IP
        $territory = $this->geoService->getCountry($request->ip());
        if (!$track->canStream($territory)) {
            return response()->json(['error' => 'not_available'], 451);
        }

        // Signed URL на 60 секунд — достатньо для початку буферизації
        $url = $this->cdn->signedUrl(
            path: "hls/{$trackId}/master.m3u8",
            ttl: 60,
            ip: $request->ip() // прив'язка до IP
        );

        // Логуємо прослуховування для роялті
        StreamEvent::dispatch($trackId, $request->user()->id, now());

        return response()->json(['url' => $url]);
    }
}

Офлайн та Progressive Web App

Для мобільного PWA — кеширування через Service Worker:

// sw.js: кешируємо сегменти для офлайну
const AUDIO_CACHE = 'audio-v1';

self.addEventListener('fetch', event => {
  const url = new URL(event.request.url);

  if (url.pathname.includes('/hls/') && url.pathname.endsWith('.aac')) {
    event.respondWith(
      caches.open(AUDIO_CACHE).then(async cache => {
        const cached = await cache.match(event.request);
        if (cached) return cached;

        const response = await fetch(event.request);
        if (isInUserLibrary(url)) {
          cache.put(event.request, response.clone());
        }
        return response;
      })
    );
  }
});

Масштабування та CDN

HLS-сегменти — статичні файли, ідеально для CDN. Але: при пиковій навантаженості (новий релиз популярного виконавця) потрібен origin shield — проміжний кеш між CDN та origin, щоб не положити S3/хранилище.

User → CDN Edge (Cloudflare/CloudFront) → Origin Shield → S3/MinIO

Манівфести .m3u8 кешуються з коротким TTL (5–30 сек) — вони змінюються при live. Сегменти .aac/.ts кешуються агресивно (365 днів, immutable), тому що імена включають хеш.

Роялті та статистика

Для кожного прослуховування потрібно рахувати секунди (не просто факт відтворення). Threshold зазвичай 30 секунд по стандартах IFPI.

# Агрегація стрімів для роялті-звітів
@dataclass
class PlaybackEvent:
    track_id: int
    user_id: int
    seconds_played: int
    quality: str  # '128k', '256k', 'lossless'
    timestamp: datetime

def aggregate_streams(events: list[PlaybackEvent]) -> dict:
    from collections import defaultdict
    counts = defaultdict(int)

    for e in events:
        if e.seconds_played >= 30:
            counts[e.track_id] += 1

    return dict(counts)

Пошук по каталогу

Elasticsearch для повнотекстового пошуку з аналізом транслітерації та фонетики:

PUT /tracks
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "phonetic": { "type": "text", "analyzer": "phonetic_analyzer" },
          "autocomplete": { "type": "search_as_you_type" }
        }
      },
      "artist": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
      "genre": { "type": "keyword" },
      "release_date": { "type": "date" },
      "play_count": { "type": "long" }
    }
  }
}

Часові рамки

Базовий стриминг з каталогом, плеєром (HLS, waveform), плейлистами та авторизацією — 10–14 тижнів. Додавання системи прав, роялті-учету та DRM — ще 6–8 тижнів. Рекомендаційний рушій, офлайн-режим PWA, мобільні приложення — окремі треки, оцінюються незалежно.