🛠️ Moonlight Developer Docs

Integruj nasze odtwarzacze muzyczne z własną stroną

🚀 Quick Start Guide

1. Podstawowa integracja

Dodaj nasze pliki do swojej strony i stwórz odtwarzacz w kilku linijkach:

<!-- Dodaj style CSS -->
<link rel="stylesheet" href="https://howtodraw.pl/css/moonlight-music-player-light.css">

<!-- Kontener dla playera -->
<div id="music-player"></div>

<!-- Dodaj skrypt -->
<script src="https://howtodraw.pl/js/MoonlightMusicPlayerLight.js"></script>

<script>
// Utwórz odtwarzacz
const player = new MoonlightMusicPlayerLight('#music-player', {
    height: 120,
    showDownload: true,
    showShare: true
});

// Załaduj utwór
player.loadTrack({
    id: 123,
    title: "Nazwa utworu",
    artist: "Nazwa artysty", 
    audioUrl: "https://howtodraw.pl/api/music/tracks/123/stream",
    waveform: [0.2, 0.5, 0.8, 0.3, 0.7, ...], // opcjonalne
    moonlightUrl: "https://howtodraw.pl/music/tracks/123" // link powrotu
});
</script>

✅ Gotowe! Twoja strona ma teraz pełnofunkcjonalny odtwarzacz muzyczny z Moonlight.

🎵 Moonlight Music Player Light

🎬 Live Demo

⚙️ Opcje konfiguracji

Opcja Typ Domyślna Opis
height number 120 Wysokość playera w pikselach
showDownload boolean true Pokazuj przycisk pobierania
showShare boolean true Pokazuj przycisk udostępniania
showVolumeControl boolean true Pokazuj kontrolę głośności
compactMode boolean false Tryb kompaktowy dla małych przestrzeni
autoPlay boolean false Automatyczne odtwaranie po załadowaniu

📋 Format danych utworu

const trackData = {
    id: 123,                    // ID utworu (wymagane)
    title: "Nazwa utworu",     // Tytuł (wymagane)
    artist: "Nazwa artysty",   // Artysta (wymagane)
    audioUrl: "https://...",   // URL do pliku audio (wymagane)
    
    // Opcjonalne:
    waveform: [0.2, 0.5, ...], // Dane waveform (array liczb 0-1)
    duration: 180,              // Długość w sekundach
    coverUrl: "https://...",    // URL okładki
    moonlightUrl: "https://...", // Link do strony na Moonlight
    genre: "Electronic",        // Gatunek muzyczny
    description: "Opis..."      // Opis utworu
};

🔗 System Embedowania

🌍 Cross-Origin Setup

Nasz system embedowania działa z dowolnych domen dzięki prawidłowej konfiguracji CORS:

✅ Dozwolone:

  • • Wszystkie domeny i subdomeny
  • • HTTP i HTTPS
  • • Localhost (development)
  • • IP addresses
  • Publiczne treści - bez ograniczeń
  • Prywatne treści - z kluczem dostępu

🔧 Nagłówki CORS:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: *

💡 Tip: Player automatycznie dodaje przycisk "🌙 Visit on Moonlight" który przekierowuje na oryginalną stronę utworu na naszej platformie.

🔒 System Uprawnień Embedowania

  • Publiczne - każdy może embedować bez klucza
  • Prywatne - wymagany klucz dostępu od autora
  • Wyłączone - embedowanie niemożliwe
  • • Klucze dostępu są 32-znakowe i widoczne tylko dla autorów

📖 Czytnik komiksu na Twojej stronie

Komiks można czytać bezpośrednio u Ciebie — jeden tag <script> i element, w którym czytnik się osadzi. Widget dokłada własne style, więc nie ma czego dołączać poza tym jednym plikiem. Ramki (iframe) nie użyjesz — Moonlight wysyła frame-ancestors 'self', więc czytnik działa przez JS i CORS.

<div id="moonlight-comic-1"></div>
<script src="https://howtodraw.pl/js/MoonlightComicReaderLight.js"></script>
<script>
  new MoonlightComicReaderLight('#moonlight-comic-1', {
    comicId: 1,
    baseUrl: 'https://howtodraw.pl',
    mode: 'auto',      // 'auto' | 'webtoon' | 'classic'
    height: 720,
    theme: 'dark',     // 'dark' | 'light'
    lang: 'pl',        // 'pl' | 'en'
    embedKey: ''       // tylko dla osadzenia prywatnego
  });
</script>

✅ Co robi czytnik:

  • • Lista rozdziałów z oznaczeniem płatnych
  • • Tryb przewijany (webtoon) i stronicowany
  • • Sterowanie strzałkami w trybie stronicowanym
  • • Leniwe wczytywanie stron
  • • Podgląd i przejście do zakupu przy płatnym rozdziale
  • • Zapamiętanie zakupu po powrocie na Twoją stronę

⚠️ Warto wiedzieć:

  • • Autor musi mieć włączone osadzanie w ustawieniach komiksu
  • • Widoczne są rozdziały opublikowane i publiczne
  • • Strony z animowaną sceną otwierają się na Moonlight
  • • Odsłony z embedu liczą się do statystyk autora

🎯 Generator Kodu Embed

🔌 API Endpoints

GET Pobierz dane utworu

GET https://howtodraw.pl/api/embed/music/tracks/{id}/player-data

Zwraca wszystkie dane potrzebne do załadowania utworu w playerze.

{
  "track": {
    "id": 123,
    "title": "Nazwa utworu",
    "artist": "Nazwa artysty",
    "audioUrl": "https://howtodraw.pl/storage/music/track-123.mp3",
    "waveform": [0.2, 0.5, 0.8, ...],
    "duration": 180,
    "coverUrl": "https://howtodraw.pl/storage/covers/123.jpg",
    "moonlightUrl": "https://howtodraw.pl/music/tracks/123"
  }
}

GET Stream audio

GET https://howtodraw.pl/api/embed/music/tracks/{id}/stream

Bezpośredni stream pliku audio z odpowiednimi nagłówkami CORS.

✅ Automatycznie obsługiwane: Range requests, cache headers, CORS, content-type detection

GET Pobierz dane komiksu

GET https://howtodraw.pl/api/embed/comics/{id}/reader-data

Zwraca dane opisowe opublikowanego komiksu: tytuł, autora, opis, okładkę, liczbę rozdziałów i link powrotny na Moonlight. Prywatne osadzenie wymaga parametru ?key=... z kluczem z ustawień komiksu.

{
  "comic": {
    "id": 1,
    "title": "Tytuł komiksu",
    "author": "Autor",
    "description": "Opis...",
    "coverUrl": "https://howtodraw.pl/storage/comics/1/cover/cover.jpg",
    "moonlightUrl": "https://howtodraw.pl/comics/1",
    "chapterCount": 12,
    "status": "ongoing",
    "readingMode": "webtoon"
  }
}

ℹ️ Zakres: ten endpoint podaje same metadane. Strony rozdziału serwują dwa endpointy niżej, z których korzysta czytnik do osadzenia. Gotowy kod znajdziesz w ustawieniach swojego komiksu, w sekcji „Osadzanie na innych stronach”.

GET Lista rozdziałów komiksu

GET https://howtodraw.pl/api/embed/comics/{id}/chapters

Rozdziały opublikowane i publiczne. Rozdziały płatne oraz w oknie przedpremiery też są na liście — z opisem blokady w polu lock (reason: paid lub premium) — ale ich stron ten endpoint nie wydaje. Parametr ?lang= zawęża do jednej wersji językowej, ?key= otwiera osadzenie prywatne.

GET Strony rozdziału

GET https://howtodraw.pl/api/embed/comics/{id}/chapters/{chapter}/pages

Dostęp rozstrzyga ta sama bramka, przez którą przechodzi czytnik na Moonlight, więc osadzony czytelnik nigdy nie zobaczy więcej niż czytelnik na naszej stronie. Rozdział zablokowany zwraca podgląd pierwszych stron oraz adres zakupu.

{
  "chapter": { "id": 42, "number": 7, "title": "...", "pageCount": 18, "readingMode": "webtoon" },
  "access": {
    "granted": false,
    "previewPages": 3,
    "lock": { "locked": true, "reason": "paid", "coinPrice": 50 },
    "purchaseUrl": "https://howtodraw.pl/embed/purchase/comic_chapter/42?return_to=..."
  },
  "pages": [ { "number": 1, "type": "image", "url": "https://.../page-1.jpg" } ]
}

🔑 Po zakupie: czytelnik wraca na Twoją stronę z parametrem moonlight_token. Dołącz go jako ?token= do żądania stron, a rozdział otworzy się już bez blokady. Token jest podpisany, dotyczy jednego rozdziału i jest ważny 30 dni. Nasz czytnik robi to za Ciebie.

📖 Przykłady użycia

🌐 WordPress Plugin

// functions.php
function moonlight_music_player_shortcode($atts) {
    $atts = shortcode_atts([
        'track_id' => '',
        'height' => '120'
    ], $atts);
    
    return '
    <div id="moonlight-' . $atts['track_id'] . '"></div>
    <script>
    new MoonlightMusicPlayerLight("#moonlight-' . $atts['track_id'] . '", {
        height: ' . $atts['height'] . '
    }).loadTrackById(' . $atts['track_id'] . ');
    </script>';
}
add_shortcode('moonlight_music', 'moonlight_music_player_shortcode');

Użycie: [moonlight_music track_id="123" height="120"]

⚛️ React Component

import { useEffect, useRef } from 'react';

function MoonlightPlayer({ trackId, height = 120 }) {
    const playerRef = useRef();
    
    useEffect(() => {
        const player = new MoonlightMusicPlayerLight(
            playerRef.current,
            { height }
        );
        
        player.loadTrackById(trackId);
        
        return () => player.destroy();
    }, [trackId]);
    
    return <div ref={playerRef} />;
}

📚 Książki i Komiksy z Płatnościami

💰 System Płatności dla Embedded Content

Moonlight obsługuje premium rozdziały które wymagają zapłaty w wewnętrznej walucie (Moondust 🌙). Stworzyliśmy dedykowany flow dla embedded content z automatycznym powrotem na Twoją stronę.

🎯 Jak to działa:

  1. User klika premium rozdział na Twojej stronie
  2. Przekierowanie na Moonlight z context preservation
  3. Automatyczny flow: login → kup Moondust → odblokuj
  4. Powrót na Twoją stronę z access tokenem

💎 System Monet:

  • 10 Moondust = 1 PLN
  • • Płatności przez Stripe
  • • Automatyczne odliczanie z balansu
  • • Jednorazowa płatność = dozgonny dostęp

⚡ Streamlined User Experience

Nasz system zachowuje kontekst przez cały proces płatności. User nie gubi się w przekierowaniach i automatycznie wraca na Twoją stronę po zakończeniu transakcji.

🔗 Embedding Premium Content

📖 Rozdział Książki

<!-- Link do premium rozdziału -->
<a href="https://howtodraw.pl/embed/purchase/book_chapter/123?return_to=https%3A%2F%2Ftwoja-strona.pl%2Fksiazka%2Frozdzia%C5%82-5&embed_key=optional_private_key"
   class="premium-chapter-link">
   🔐 Przeczytaj Rozdział 5 (Premium)
</a>

<!-- Lub jako button -->
<button onclick="window.location.href='https://howtodraw.pl/embed/purchase/book_chapter/123?return_to=...'">
   Odblokuj za 50 Moondust
</button>

🎨 Rozdział Komiksu

<!-- Link do premium rozdziału komiksu -->
<a href="https://howtodraw.pl/embed/purchase/comic_chapter/456?return_to=https%3A%2F%2Ftwoja-strona.pl%2Fkomiks%2Frozdzia%C5%82-10"
   class="premium-chapter-link">
   🔐 Przeczytaj Rozdział 10 (Premium)
</a>

🔄 Obsługa Powrotu

// JavaScript - obsługa powrotu po zakupie
const urlParams = new URLSearchParams(window.location.search);

if (urlParams.get('access_granted') === '1') {
    const chapterId = urlParams.get('chapter_id');
    const moonlightToken = urlParams.get('moonlight_token');
    
    // User pomyślnie odblokował rozdział
    showChapterContent(chapterId);
    
    // Opcjonalnie: zapisz token dla przyszłych requestów
    localStorage.setItem(`chapter_${chapterId}_token`, moonlightToken);
}

Potrzebujesz pomocy? 🤝

Nasz zespół pomoże Ci z integracją i odpowie na wszystkie pytania