Kontrol & Event Player (JavaScript Bridge)

Panduan mengontrol video player, melakukan jump durasi (seek), dan mendeteksi event start, pause, timeupdate, serta selesai (ended) via postMessage untuk integrasi LMS dan website kursus.

DeweStream menyediakan antarmuka komunikasi dua arah berbasis peramban bernama Embed Bridge. Melalui antarmuka ini, halaman website atau platform kursus online (Learning Management System / LMS) tempat video disematkan dapat berinteraksi langsung dengan iframe video player DeweStream secara aman, ringan, dan tanpa memerlukan library eksternal tambahan.

Fitur ini dirancang khusus bagi pemilik website atau pengembang aplikasi yang ingin:

  • Melacak progres belajar siswa: Mengetahui detik berapa yang sedang ditonton secara berkala.
  • Mengaktifkan tombol penyelesaian materi secara otomatis: Mengetahui kapan siswa selesai menonton video hingga tuntas (ended).
  • Melanjutkan pemutaran (Resume Playback): Mengembalikan siswa ke menit terakhir saat mereka membuka kembali modul pelajaran.
  • Membuat daftar bab / timestamp eksternal: Menyediakan tombol atau daftar isi di luar bingkai video yang saat diklik langsung melompat (duration jump) ke menit tertentu.

Prinsip Keamanan & Prasyarat

Embed Bridge memanfaatkan API standar peramban window.postMessage. Untuk mencegah pembajakan dan kebocoran data pemutaran:

  1. Origin Verification: Player DeweStream hanya akan memproses perintah jika pesan dikirimkan oleh jendela induk (window.parent) dan berasal dari alamat domain (origin) yang diizinkan sesuai aturan Domain yang Diizinkan.
  2. Target Origin Ketat: Jangan pernah menggunakan tanda bintang (*) sebagai target pengiriman postMessage. Selalu tentukan origin player DeweStream secara eksplisit (misalnya https://app.dewe.stream).
  3. Versi Protokol: Semua komunikasi pesan menggunakan nomor versi kontrak terstruktur (version: 1).

1. Mendeteksi Event dari Player (Outbound Events)

Saat video dimuat dan diputar di dalam iframe, player DeweStream secara berkala memancarkan data status ke halaman website induk Anda. Anda dapat menangkap data tersebut menggunakan pendengar event (event listener) pada jendela peramban.

Struktur Pesan dari Player

Setiap pesan yang dipancarkan oleh player memiliki struktur data JSON berikut:

typescript
{
  type: 'dewe-stream:ready' | 'dewe-stream:state' | 'dewe-stream:timeupdate',
  version: 1,
  videoId: string,          // UUID unik video yang sedang diputar
  currentTime: number,      // Posisi waktu pemutaran saat ini (dalam detik)
  duration: number | null,  // Durasi total video (dalam detik)
  paused: boolean,          // true jika video sedang dijeda, false jika sedang berjalan
  ended: boolean,           // true jika video telah selesai diputar sampai akhir
  chapters?: Array<{        // Hanya disertakan pada event 'dewe-stream:ready'
    id: string,
    title: string,
    startSeconds: number
  }>
}

Jenis-Jenis Event

  • dewe-stream:ready: Dipancarkan satu kali segera setelah metadata video (durasi dan daftar bab) berhasil dimuat. Ini adalah momen yang tepat untuk mengecek riwayat tontonan siswa dan melompatkan posisi video (resume playback).
  • dewe-stream:state: Dipancarkan setiap kali terjadi perubahan status pemutaran video, meliputi:
    • Mulai / Memutar (Play): Nilai paused: false dan ended: false. Jika currentTime bernilai 0, berarti video baru pertama kali dimulai.
    • Jeda (Pause): Nilai paused: true dan ended: false.
    • Selesai (Ended): Nilai ended: true.
    • Selesai Melompat (Seeked): Nilai waktu currentTime telah berpindah ke posisi baru.
  • dewe-stream:timeupdate: Dipancarkan secara kontinu mengikuti pemutaran video (beberapa kali per detik). Berisi nilai currentTime terbaru. Disarankan menggunakan teknik debounce (misalnya menyimpan posisi tiap 10–15 detik) jika Anda mencatat progres ke database server Anda.

2. Mengontrol Player (Inbound Seek Command)

Untuk memerintahkan player melompat ke menit tertentu (seek / duration jump), kirimkan objek perintah melalui postMessage ke contentWindow milik elemen iframe:

javascript
playerIframe.contentWindow.postMessage({
  type: 'dewe-stream:seek',
  seconds: 125,     // Detik tujuan yang ingin dituju (angka >= 0)
  videoId: '...',   // Opsional: UUID video untuk memastikan kecocokan
  play: true        // Opsional: true jika ingin langsung diputar setelah melompat
}, playerOrigin);
  • seconds (Wajib): Posisi detik tujuan pemutaran. Jika detik yang diminta melebihi durasi video, player otomatis membatasi ke durasi maksimal video.
  • play (Opsional): Jika diisi true, player akan otomatis mencoba melanjutkan pemutaran. Aturan autoplay peramban tetap berlaku jika pengguna belum pernah berinteraksi dengan video.

3. Contoh Implementasi Praktis

Berikut adalah contoh kode HTML dan JavaScript siap pakai yang menggabungkan kontrol lompat durasi dan pemantauan status video untuk kebutuhan LMS.

html
<!-- Elemen Iframe DeweStream -->
<iframe
  id="dewe-player"
  src="https://app.dewe.stream/embed/00000000-0000-0000-0000-000000000000"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen
  style="width: 100%; aspect-ratio: 16/9; border: 0; border-radius: 8px;"
></iframe>

<!-- Kontrol Eksternal Halaman -->
<div style="margin-top: 16px; display: flex; gap: 8px; align-items: center;">
  <button id="btn-jump-intro">Lompat ke Materi Inti (02:30)</button>
  <button id="btn-complete" disabled>Tandai Modul Selesai</button>
</div>
<p id="player-status" style="margin-top: 8px; color: #64748b; font-size: 14px;">
  Status: Memuat player...
</p>

<script>
  const iframe = document.getElementById('dewe-player');
  const playerOrigin = new URL(iframe.src).origin;
  const statusEl = document.getElementById('player-status');
  const completeBtn = document.getElementById('btn-complete');
  const jumpBtn = document.getElementById('btn-jump-intro');

  let activeVideoId = '';

  // 1. DENGARKAN EVENT DARI PLAYER
  window.addEventListener('message', (event) => {
    // Pastikan pesan hanya diterima dari iframe DeweStream yang sah
    if (event.source !== iframe.contentWindow || event.origin !== playerOrigin) {
      return;
    }

    const data = event.data;
    if (!data || data.version !== 1) return;

    switch (data.type) {
      case 'dewe-stream:ready':
        activeVideoId = data.videoId;
        statusEl.textContent = `Player siap. Durasi: ${Math.round(data.duration)} detik.`;
        
        // Contoh: Melanjutkan dari posisi tersimpan (misal detik ke-30)
        // seekPlayer(30, false);
        break;

      case 'dewe-stream:state':
        if (data.ended) {
          statusEl.textContent = 'Status: Video selesai ditonton 100%.';
          // Buka akses tombol penyelesaian modul materi
          completeBtn.disabled = false;
          completeBtn.style.backgroundColor = '#16a34a';
          completeBtn.style.color = '#ffffff';
        } else if (data.paused) {
          statusEl.textContent = `Status: Dijeda pada detik ke-${Math.round(data.currentTime)}.`;
        } else {
          statusEl.textContent = `Status: Sedang memutar... (${Math.round(data.currentTime)}s)`;
        }
        break;

      case 'dewe-stream:timeupdate':
        // Pantau progres untuk keperluan analitik lokal
        break;
    }
  });

  // 2. FUNGSI UNTUK MELOMPATKAN WAKTU VIDEO (SEEK)
  function seekPlayer(targetSeconds, autoPlay = true) {
    iframe.contentWindow.postMessage({
      type: 'dewe-stream:seek',
      videoId: activeVideoId,
      seconds: targetSeconds,
      play: autoPlay
    }, playerOrigin);
  }

  // Event klik tombol lompat durasi (misalnya ke detik 150 = 2 menit 30 detik)
  jumpBtn.addEventListener('click', () => {
    seekPlayer(150, true);
  });

  completeBtn.addEventListener('click', () => {
    alert('Selamat! Anda telah menyelesaikan materi pelajaran ini.');
  });
</script>

4. Rekomendasi Alur Integrasi LMS

Untuk memastikan pengalaman belajar siswa yang mulus:

  1. Gunakan ended: true sebagai Tolok Ukur Penyelesaian: Jangan membandingkan kesetaraan desimal currentTime === duration karena perbedaan presisi peramban dapat menyebabkan selisih beberapa milidetik. Gunakan selalu kondisi data.ended === true dari event dewe-stream:state.
  2. Penyimpanan Progres Berkala: Hindari mengirim request HTTP ke server Anda di setiap event timeupdate. Simpan waktu terakhir ke variabel lokal, dan kirimkan rekaman progres ke server secara berkala (misal setiap 10–15 detik) serta saat event jeda (pause) atau saat siswa menutup halaman (pagehide).
  3. Resume Cerdas: Jika posisi terakhir siswa tersimpan di detik-detik paling akhir video (misalnya 3 detik sebelum selesai), lakukan resume beberapa detik lebih awal agar siswa tetap dapat melihat akhir video dan memicu status selesai secara natural.

Panduan Terkait

Last updated Oct 20, 2026