# IFrame Player API


IFrame Player API позволяет программно управлять плеером через JavaScript: запускать и останавливать воспроизведение, управлять громкостью, подписываться на события и многое другое.

## Кому подходит эта статья

* **Frontend-разработчикам** — нужно программно управлять плеером на странице
* **Разработчикам LMS** — требуется отслеживать прогресс обучения и создавать интерактивные сценарии
* **Разработчикам приложений** — нужно интегрировать плеер с бизнес-логикой приложения

## Зачем нужен IFrame Player API?

С помощью IFrame Player API вы можете:

* **Программно управлять плеером** — запускать, останавливать, перематывать видео
* **Реагировать на события** — отслеживать начало воспроизведения, паузы, окончание видео
* **Создавать интерактивные сценарии** — синхронизировать плеер с другими элементами страницы
* **Управлять плейлистами** — динамически переключаться между видео
* **Настраивать параметры** — изменять качество, громкость, скорость воспроизведения программно

## Что полезного даёт IFrame Player API

IFrame Player API помогает связать плеер с логикой вашего приложения: вы управляете воспроизведением и подписываетесь на события.

### Управление и события

* **Связь с логикой приложения** — вы можете привязать управление плеером к состоянию пользователя, правам доступа и другим условиям в вашем продукте.
* **Promise-интерфейс** — методы API возвращают Promise, поэтому их удобно вызывать через `await` или `.then()`.
* **События плеера** — подписка на события (play/pause/ended и др.) позволяет запускать действия в вашем интерфейсе в нужный момент.

### Свои метрики и отправка данных

* **Контекст в аналитике** — вы можете дополнять события своими данными (например, ID пользователя, курс, урок, устройство, браузер).
* **Детальные события** — при необходимости учитывайте паузы, перемотки, повторные просмотры и другие действия.
* **Экспорт в ваши системы** — отправляйте собранные события в вашу аналитику, CRM или LMS.

### Параметры и сценарии

* **Изменение параметров на лету** — меняйте громкость, скорость, качество и другие настройки, когда это нужно по контексту.
* **Сценарии поверх видео** — делайте интерактивные механики (квизы, переходы, подсказки) в связке с событиями плеера.

## Типичные сценарии использования

### Системы обучения (LMS)

IFrame Player API особенно полезен для образовательных платформ, где важно учитывать множество факторов:

* **Отслеживание прогресса обучения** — фиксация времени просмотра, завершения уроков, повторных просмотров
* **Адаптивное обучение** — автоматический переход к следующему уроку после завершения текущего
* **Проверка знаний** — остановка воспроизведения для показа вопросов в определённые моменты
* **Персонализация** — настройка скорости воспроизведения, качества видео и других параметров под предпочтения студента
* **Интеграция с системой оценок** — связь просмотра видео с оценками и достижениями

### Интерактивные приложения

* **Синхронизация с контентом** — показ дополнительной информации, комментариев или субтитров в определённые моменты видео
* **Интеграция с формами** — остановка воспроизведения для заполнения форм или прохождения опросов
* **Многоэкранные сценарии** — управление несколькими плеерами на одной странице

### Корпоративные порталы

* **Контроль доступа** — проверка прав пользователя перед воспроизведением
* **Логирование активности** — детальное отслеживание использования контента сотрудниками
* **Интеграция с внутренними системами** — связь просмотра видео с задачами, проектами, отчётами

## Пример: Расширенная аналитика для систем обучения

Вот пример создания системы аналитики, которая собирает данные о просмотре видео и обогащает их контекстной информацией:

```javascript
// Система аналитики для образовательной платформы
class LearningAnalytics {
  constructor(player, context) {
    this.player = player;
    this.context = {
      userId: context.userId,
      courseId: context.courseId,
      lessonId: context.lessonId,
      device: this.getDeviceInfo(),
      browser: this.getBrowserInfo(),
      timestamp: new Date().toISOString()
    };
    this.events = [];
    this.setupEventListeners();
  }

  setupEventListeners() {
    const player = this.player;

    // Отслеживание начала воспроизведения
    player.on(player.Events.Play, () => {
      this.trackEvent('play', {
        currentTime: null, // получим при следующем TimeUpdate
        playbackRate: null
      });
    });

    // Отслеживание паузы
    player.on(player.Events.Pause, async () => {
      const currentTime = await player.getCurrentTime();
      const duration = await player.getDuration();
      const percent = (currentTime / duration) * 100;

      this.trackEvent('pause', {
        currentTime,
        percent,
        reason: this.detectPauseReason() // например, "user_action", "network_issue"
      });
    });

    // Отслеживание прогресса просмотра
    let lastTrackedPercent = 0;
    player.on(player.Events.TimeUpdate, async (event) => {
      const percent = event.data.percent;
      
      // Отправляем событие каждые 10% просмотра
      if (percent - lastTrackedPercent >= 10) {
        lastTrackedPercent = percent;
        this.trackEvent('progress', {
          percent: Math.floor(percent),
          currentTime: event.data.currentTime
        });
      }
    });

    // Отслеживание завершения просмотра
    player.on(player.Events.Ended, async () => {
      const duration = await player.getDuration();
      this.trackEvent('completed', {
        totalDuration: duration,
        watchedDuration: duration // можно вычислить из событий паузы
      });
    });

    // Отслеживание перемотки
    let lastSeekTime = 0;
    player.on(player.Events.Seeked, async () => {
      const currentTime = await player.getCurrentTime();
      if (Math.abs(currentTime - lastSeekTime) > 5) {
        this.trackEvent('seek', {
          from: lastSeekTime,
          to: currentTime,
          direction: currentTime > lastSeekTime ? 'forward' : 'backward'
        });
      }
      lastSeekTime = currentTime;
    });

    // Отслеживание изменения качества
    player.on(player.Events.QualityChanged, (event) => {
      this.trackEvent('quality_changed', {
        quality: event.data.quality,
        reason: 'user_selection' // или 'auto_adaptation'
      });
    });

    // Отслеживание ошибок
    player.on(player.Events.Error, (event) => {
      this.trackEvent('error', {
        error: event.data.error,
        currentTime: null // можно получить асинхронно
      });
    });
  }

  trackEvent(eventType, eventData) {
    const event = {
      type: eventType,
      data: eventData,
      context: this.context,
      timestamp: new Date().toISOString()
    };

    this.events.push(event);
    
    // Отправка события в вашу систему аналитики
    this.sendToAnalytics(event);
  }

  async sendToAnalytics(event) {
    // Пример отправки в вашу систему аналитики
    try {
      await fetch('/api/analytics/track', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(event)
      });
    } catch (error) {
      console.error('Ошибка отправки аналитики:', error);
      // Можно сохранить в локальное хранилище для повторной отправки
    }
  }

  detectPauseReason() {
    // Логика определения причины паузы
    // Например, проверка сетевого соединения, активности пользователя и т.д.
    return 'user_action';
  }

  getDeviceInfo() {
    return {
      type: /Mobile|Android|iPhone|iPad/.test(navigator.userAgent) ? 'mobile' : 'desktop',
      screen: {
        width: window.screen.width,
        height: window.screen.height
      }
    };
  }

  getBrowserInfo() {
    return {
      name: navigator.userAgent.match(/(Chrome|Firefox|Safari|Edge)\/[\d.]+/)?.[1] || 'unknown',
      version: navigator.userAgent.match(/(Chrome|Firefox|Safari|Edge)\/([\d.]+)/)?.[2] || 'unknown'
    };
  }

  // Получить сводку по просмотру
  getSummary() {
    return {
      totalEvents: this.events.length,
      events: this.events,
      context: this.context
    };
  }
}

// Использование системы аналитики
function onKinescopeIframeAPIReady(playerFactory) {
  playerFactory
    .create('player', {
      url: 'https://kinescope.io/1111111',
      size: { width: '100%', height: 400 }
    })
    .then(function (player) {
      // Инициализация системы аналитики с контекстом обучения
      const analytics = new LearningAnalytics(player, {
        userId: 'user_12345',
        courseId: 'course_67890',
        lessonId: 'lesson_11111',
        // Можно добавить дополнительные данные:
        // studentLevel: 'beginner',
        // language: 'ru',
        // timeOfDay: new Date().getHours()
      });

      // Пример: отправка сводки при закрытии страницы
      window.addEventListener('beforeunload', () => {
        const summary = analytics.getSummary();
        // Отправка финальной сводки
        navigator.sendBeacon('/api/analytics/track', JSON.stringify({
          type: 'session_end',
          summary: summary
        }));
      });
    });
}
```

Этот пример показывает, как можно:

* **Собирать детальные данные** о просмотре видео с привязкой к контексту обучения
* **Обогащать события** информацией о пользователе, курсе, устройстве и других факторах
* **Отслеживать различные метрики** — время просмотра, паузы, перемотки, качество видео
* **Интегрироваться с вашей системой** — отправка данных в вашу аналитику, LMS или другие системы

## Интеграция с внутренней логикой приложения

IFrame Player API позволяет легко интегрировать плеер с внутренней логикой вашего приложения:

### Пример: Управление доступом

```javascript
function onKinescopeIframeAPIReady(playerFactory) {
  // Проверка прав доступа перед созданием плеера
  checkUserAccess()
    .then(hasAccess => {
      if (!hasAccess) {
        showAccessDeniedMessage();
        return;
      }

      return playerFactory.create('player', {
        url: 'https://kinescope.io/1111111',
        size: { width: '100%', height: 400 }
      });
    })
    .then(function (player) {
      if (!player) return;

      // Дополнительная логика после создания плеера
      setupPlayerLogic(player);
    });
}

async function checkUserAccess() {
  // Проверка прав доступа через ваш API
  const response = await fetch('/api/check-access');
  const data = await response.json();
  return data.hasAccess;
}

function setupPlayerLogic(player) {
  // Логика, связанная с вашим приложением
  player.on(player.Events.Ended, async () => {
    // Обновление прогресса в вашей системе
    await updateUserProgress();
    
    // Разблокировка следующего урока
    await unlockNextLesson();
    
    // Показ уведомления
    showNotification('Урок завершён!');
  });
}
```

### Пример: Синхронизация с состоянием приложения

```javascript
// Интеграция с состоянием React/Vue/Angular приложения
function createPlayerWithState(playerFactory, appState) {
  return playerFactory.create('player', {
    url: appState.currentVideo.url,
    behavior: {
      autoPlay: appState.settings.autoPlay,
      muted: appState.settings.muted
    }
  }).then(function (player) {
    // Синхронизация состояния плеера с состоянием приложения
    player.on(player.Events.Pause, () => {
      appState.setPlayerState('paused');
    });

    player.on(player.Events.Playing, () => {
      appState.setPlayerState('playing');
    });

    // Обновление плеера при изменении состояния приложения
    appState.on('videoChanged', (newVideo) => {
      player.switchTo(newVideo.id);
    });

    return player;
  });
}
```

## Подключение API

Для использования IFrame Player API необходимо подключить скрипт на страницу и объявить функцию `onKinescopeIframeAPIReady`, которая будет вызвана автоматически после загрузки API.

### Базовый пример подключения

```html
<!doctype html>
<html>
  <body>
    <!-- Контейнер для плеера -->
    <div id="player"></div>

    <script>
      // Подключение скрипта IFrame Player API
      var tag = document.createElement('script');
      tag.src = 'https://player.kinescope.io/latest/iframe.player.js';
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // Функция будет вызвана автоматически после загрузки API
      function onKinescopeIframeAPIReady(playerFactory) {
        // Создание плеера
        playerFactory
          .create('player', {
            url: 'https://kinescope.io/1111111',
            size: { width: '100%', height: 400 },
          })
          .then(function (player) {
            console.log('Плеер создан:', player);
          });
      }
    </script>
  </body>
</html>
```

## Создание плеера

Для создания плеера используется метод `create` объекта `playerFactory`:

```javascript
playerFactory.create(elementId, options).then(function(player) {
  // Плеер готов к использованию
});
```

### Параметры создания

* **`elementId`** — ID элемента на странице, который будет заменён на iframe (или ID существующего iframe)
* **`options`** — объект с настройками плеера

#### Основные параметры

```javascript
{
  // URL видео (обязательный параметр)
  url: 'https://kinescope.io/1111111',
  
  // Размеры плеера
  size: {
    width: '100%',  // или число в пикселях
    height: 400     // или строка '56.25%' для соотношения 16:9
  },
  
  // Настройки поведения
  behavior: {
    preload: 'metadata',  // 'none', 'metadata', 'auto'
    autoPlay: false,      // автоматический запуск
    muted: false,         // выключить звук
    loop: false,          // зациклить видео
    keyboard: true,       // управление с клавиатуры
    playsInline: true     // воспроизведение на мобильных без полноэкранного режима
  },
  
  // Настройки UI
  ui: {
    language: 'ru',        // 'ru' или 'en'
    controls: true,       // показывать элементы управления
    mainPlayButton: true  // большая кнопка Play в центре
  }
}
```

### Пример создания плеера с настройками

```javascript
function onKinescopeIframeAPIReady(playerFactory) {
  playerFactory
    .create('player', {
      url: 'https://kinescope.io/1111111',
      size: {
        width: '100%',
        height: '56.25%'  // Соотношение 16:9
      },
      behavior: {
        preload: 'metadata',
        autoPlay: false,
        muted: false
      },
      ui: {
        language: 'ru',
        controls: true
      }
    })
    .then(function (player) {
      // Плеер создан и готов к использованию
      console.log('Плеер готов');
    });
}
```

## Управление плеером

После создания плеера вы получаете объект `player` с методами для управления воспроизведением.

### Основные методы управления

#### Воспроизведение

```javascript
// Начать воспроизведение
await player.play();

// Приостановить воспроизведение
await player.pause();

// Остановить воспроизведение (вернуться в начало)
await player.stop();

// Перемотать на указанное время (в секундах)
await player.seekTo(60);  // перемотать на 1 минуту
```

#### Получение информации

```javascript
// Проверить, на паузе ли плеер
const isPaused = await player.isPaused();

// Проверить, закончилось ли воспроизведение
const isEnded = await player.isEnded();

// Получить текущее время воспроизведения (в секундах)
const currentTime = await player.getCurrentTime();

// Получить длительность видео (в секундах)
const duration = await player.getDuration();
```

#### Управление громкостью

```javascript
// Получить текущую громкость (0..1, где 0 это 0%, а 1 это 100%)
const volume = await player.getVolume();

// Установить громкость (0..1)
await player.setVolume(0.5);  // установить 50%

// Выключить звук
await player.mute();

// Включить звук
await player.unmute();

// Проверить, выключен ли звук
const isMuted = await player.isMuted();
```

#### Управление CTA

```javascript
// Закрыть экран CTA программно
await player.closeCTA();
```

#### Управление качеством

```javascript
// Получить список доступных качеств
const qualities = await player.getVideoQualityList();

// Получить текущее качество
const currentQuality = await player.getVideoQuality();

// Установить качество
await player.setVideoQuality('1080p');
```

#### Управление скоростью воспроизведения

```javascript
// Получить текущую скорость (1 - нормальная скорость)
const playbackRate = await player.getPlaybackRate();

// Установить скорость воспроизведения
await player.setPlaybackRate(1.5);  // 1.5x скорость
```

#### Полноэкранный режим

```javascript
// Проверить, активен ли полноэкранный режим
const isFullscreen = await player.isFullscreen();

// Включить/выключить полноэкранный режим
await player.setFullscreen(true);
```

#### Режим "картинка в картинке"

```javascript
// Проверить, активен ли режим PiP
const isPip = await player.isPip();

// Включить/выключить режим PiP
await player.setPip(true);
```

### Пример использования методов

```javascript
function onKinescopeIframeAPIReady(playerFactory) {
  playerFactory
    .create('player', {
      url: 'https://kinescope.io/1111111',
      size: { width: '100%', height: 400 }
    })
    .then(function (player) {
      // Установить громкость на 50%
      player.setVolume(0.5);
      
      // Подписаться на событие начала воспроизведения
      player.on(player.Events.Playing, function() {
        console.log('Воспроизведение началось');
      });
      
      // Подписаться на событие паузы
      player.on(player.Events.Pause, function() {
        console.log('Воспроизведение приостановлено');
      });
      
      // Подписаться на изменение времени
      player.on(player.Events.TimeUpdate, function(event) {
        console.log('Текущее время:', event.data.currentTime);
      });
    });
}
```

## События плеера

Плеер генерирует события, на которые можно подписаться для отслеживания изменений состояния.

### Подписка на события

```javascript
// Подписаться на событие (обработчик будет вызываться каждый раз)
player.on(player.Events.Play, function(event) {
  console.log('Воспроизведение запущено');
});

// Подписаться на событие один раз
player.once(player.Events.Loaded, function(event) {
  console.log('Плеер загружен');
});

// Отписаться от события
function handler(event) {
  console.log('Событие произошло');
}
player.on(player.Events.Play, handler);
player.off(player.Events.Play, handler);
```

### Основные события

* **`Events.Loaded`** — плеер загрузил все необходимые данные и готов к воспроизведению
* **`Events.Play`** — запуск воспроизведения
* **`Events.Playing`** — воспроизведение началось
* **`Events.Pause`** — пауза
* **`Events.Ended`** — окончание воспроизведения
* **`Events.TimeUpdate`** — изменение текущего времени воспроизведения
* **`Events.VolumeChange`** — изменение уровня звука
* **`Events.QualityChanged`** — изменение качества видео
* **`Events.FullscreenChange`** — изменение полноэкранного режима
* **`Events.CallAction`** — нажатие на кнопку призыва к действию (CTA)
* **`Events.Error`** — критическая ошибка

### Данные события

Каждое событие содержит объект с данными:

```javascript
{
  type: player.Events.Play,  // тип события
  data: { /* данные события */ },  // могут отсутствовать
  target: player  // объект плеера
}
```

### Пример работы с событиями

```javascript
player
  .once(player.Events.Loaded, function(event) {
    // Плеер загружен, можно начинать работу
    console.log('Длительность:', event.data.duration);
    console.log('Качество:', event.data.quality);
  })
  .on(player.Events.TimeUpdate, function(event) {
    // Обновление времени воспроизведения
    const currentTime = event.data.currentTime;
    const percent = event.data.percent;
    console.log(`Воспроизведено: ${currentTime} сек (${percent}%)`);
  })
  .on(player.Events.Ended, function() {
    // Видео закончилось
    console.log('Воспроизведение завершено');
  })
  .on(player.Events.Error, function(event) {
    // Обработка ошибок
    console.error('Ошибка плеера:', event.data.error);
  });
```

## Работа с плейлистами

IFrame Player API поддерживает создание и управление плейлистами из нескольких видео.

### Создание плейлиста

```javascript
playerFactory
  .create('player', {
    url: 'https://kinescope.io/1111111',
    playlist: [
      {
        id: 'video1',
        title: 'Первое видео',
        subtitle: 'Описание первого видео'
      },
      {
        id: 'video2',
        title: 'Второе видео',
        subtitle: 'Описание второго видео'
      }
    ],
    behavior: {
      playlist: {
        autoSwitch: true,  // автоматическое переключение между видео
        loop: false        // повторять весь плейлист
      }
    }
  })
  .then(function(player) {
    // Плеер с плейлистом готов
  });
```

### Управление плейлистом

```javascript
// Получить текущий элемент плейлиста
const currentItem = await player.getPlaylistItem();

// Переключиться на указанное видео
await player.switchTo('video2', {
  autoPlay: true,  // автоматически начать воспроизведение
  time: 0          // начать с начала
});

// Переключиться на следующее видео
await player.next();

// Переключиться на предыдущее видео
await player.previous();

// Подписаться на событие смены видео
player.on(player.Events.CurrentTrackChanged, function(event) {
  console.log('Текущее видео:', event.data.item.id);
});
```

## Призывы к действию (CTA)

> **Внимание:**

**Beta-функция.** Может измениться после сбора отзывов.



Call To Action (CTA) позволяет показывать призывы к действию во время воспроизведения видео. Это полезно для рекламы, подписок, регистраций или других целей.

**Как это работает:** При активации CTA проигрывание останавливается и показывается экран поверх плеера с призывом к действию. При нажатии пользователем на кнопку действия срабатывает событие, которое можно обработать программно.

CTA может быть настроен для показа:
* В конце видео или плейлиста
* В определённые моменты воспроизведения
* При паузе видео

### Настройка CTA через IFrame API

Для настройки CTA используйте параметр `playlist` при создании плеера. Подробнее о всех возможностях API см. в [полной документации](https://docs.kinescope.io/player/latest/embed/iframe-api/).

**Пример настройки CTA:**

```javascript
import { createPlayer } from '@kinescope/iframe-api';

const player = await createPlayer({
  videoId: '123456789',
  playlist: [
    {
      videoId: '123456789',
      cta: {
        title: 'Подпишитесь на наш канал',
        description: 'Получайте новые видео первыми',
        buttonText: 'Подписаться',
        buttonUrl: 'https://example.com/subscribe',
        showAt: 'end' // или время в секундах
      }
    }
  ]
});
```

### Управление CTA программно

Чтобы закрыть экран CTA программно, вызовите метод `closeCTA()` у объекта плеера:

```javascript
await player.closeCTA();
```

### Обработка событий CTA

При нажатии пользователем на кнопку CTA срабатывает событие `CallAction`. Вы можете подписаться на это событие для отслеживания взаимодействий:

```javascript
player.on(player.Events.CallAction, function(event) {
  console.log('CTA clicked:', event.data);
  // Ваша логика обработки
});
```

Подробнее о параметрах создания плеера через IFrame API см. в [полной документации](https://docs.kinescope.io/player/latest/embed/iframe-api/iframe-player-factory/), а о событиях плеера — в [документации по событиям](https://docs.kinescope.io/player/latest/embed/iframe-api/iframe-player-api/#event-data).

## TypeScript типы

Для удобства разработки доступна библиотека с TypeScript типами:

```bash
npm install @kinescope/player-iframe-api-loader
```

Подробнее о библиотеке и типах см. на [GitHub](https://github.com/kinescope/player-iframe-api-loader).

## Рекомендации

* **Не храните объект плеера в глобальной переменной** — это может создать проблемы безопасности
* **Используйте `await` или `.then()`** — все методы API возвращают Promise
* **Отписывайтесь от событий** — при удалении плеера не забудьте отписаться от всех событий
* **Обрабатывайте ошибки** — подписывайтесь на событие `Events.Error` для обработки критических ошибок

## Полная документация

Для получения полной информации о всех методах, событиях и параметрах API обратитесь к [полной документации IFrame Player API](https://docs.kinescope.io/player/latest/embed/iframe-api/).

## Что дальше?

Если хотите продолжить:

1. **[Аналитика](https://docs.kinescope.ru/katalog-i-upravlenie-video/analitika/)** — как собирать метрики и связывать их с вашим контекстом (пользователь, курс, урок и т.д.)
2. **[Кастомизация плеера](https://docs.kinescope.ru/videopleer-nastrojka-i-vstraivanie/kastomizatsiya-pleera/)** — настройка внешнего вида и поведения плеера
3. **[Встраивание](https://docs.kinescope.ru/videopleer-nastrojka-i-vstraivanie/vstraivanie/)** — базовое встраивание плеера без API
4. **[Решение проблем](https://docs.kinescope.ru/diagnostika-i-podderzhka/reshenie-problem/)** — типичные проблемы при работе с API

Если остались вопросы, напишите в [чат поддержки](https://t.me/kinescope_bot) — специалисты помогут!

