# player
Panjareh using aparat and phoenix-video-player to play videos on desktops and tvs. 

 
> how it works?
> detect device from its User Agent string, and render view
> according to the detected device type.


# tech
- [@filmgardi/aparat](https://git.ayeneh.co/filmgardi/frontend/web/player/aparat) - suitable player for desktop browsers
- [@filmgardi/phoenix-video-player](https://git.ayeneh.co/filmgardi/frontend/web/phoenix-player) - suitable player for tv browsers 
- [@filmgardi/videojs-phoenix-theme](https://git.ayeneh.co/filmgardi/frontend/web/player-plugins/videojs-phoenix-theme) - theme for players

# Player Options
These are the available config options for player.

```
{
  autoplay: true,
  controls: true,
  fill: true,
  playbackRates: [0.5, 1, 1.25, 1.5],
  language: "fa",
  poster: "",
  sources: [],
  info: { title: null, subTitle: null },
  returnUrl: null,
  html5: {
    nativeTextTracks: isMobileSafari ? true : false,

    // To using phoenix-player hlsjs config is required
    hlsjsConfig: {
      // Put your hls.js config here  
      debug: true,
      enableWorker: true,
      lowLatencyMode: true,
      backBufferLength: 90,
      maxBufferSize: 60 * 1000 * 1000,
      startLevel: 0,
    },
  },

  // To init external plugins if have one
  initPlugins: {
     seekButtons,
     vttThumbnails
  },

  // Customize control bar components
  controlBar: { children: ['playToggle'] },

  pluginOptions: {
    // Put your plugin options config here
  }
}
```

## Plugin Options

These are the available config options for plugins. you can enable these plugins by adding its object to PluginOptions.

### Progress Bar Seek Thumbnail

```
seekThumbnailSrc: null
```

### Seek Forward

```
seekButtons: {
  forward: 10,
  back: 10,
  forwardIndex: 1,
  backIndex: 1,
}
```
### Next Episode

```
nextEpisode: {
  showAutoAdvanceButton: true,
  autoAdvanceButtonText: "قسمت بعدی",
  autoAdvance: true,
  // auto advanced button url
  url: "",

  // auto advance button display on certain time
  nextEpisodeDisplayTime: null,
  nextEpisodeDisplayDuration: 10,

  // dialog options that opens from menu
  placementIndex: 9,
  dialogData: {
    title: "",
    description: "",
    url: ``,
  },
  dialogTemplate: ({ title, description, url }) => {
    const container = document.createElement("div");
    container.className = "vjs-next-episode-dialog-content";
    container.style.flexDirection = "row";
    container.style.alignItems = "self-end";
    container.style.width = "420px";
    container.style.padding = "12px 24px";
    
    const img = document.createElement("img");
    img.className = "vjs-next-episode-dialog-poster";
    img.src = url;
    img.style.width = "140px";
    img.style.height = "65px";
    img.style.marginLeft = "24px";
    container.appendChild(img);

    const episodeContent = document.createElement("div");
    episodeContent.className = "vjs-next-episode-content";
    episodeContent.style.display = "flex";
    episodeContent.style.flexDirection = "column";
    episodeContent.style.justifyContent = "end";
    episodeContent.style.textAlign = "right";
    container.appendChild(episodeContent);

    const titleEl = document.createElement("span");
    titleEl.className = "vjs-next-episode-dialog-title";
    titleEl.innerHTML = title;

    episodeContent.appendChild(titleEl);

    const descriptionEl = document.createElement("span");
    descriptionEl.className = "vjs-next-episode-dialog-description";
    descriptionEl.innerHTML = description;

    episodeContent.appendChild(descriptionEl);

    return container;
  },
}
```

### Skip Button

```
skipButton: {
  from: null, // From seconds
  to: null, // To seconds
  text: "skipOpeningCredits",
  position: "bottom-right",
  offsetH: 46,
  offsetV: 167,
}
```

### Traffic Usage Label

```
trafficUsage: {
  title: null,
  message: null,
  expireTime: 5, // Minute
  position: "top-right",
  offsetH: 30,
  offsetV: 15,
}
```

### Subtitle Settings 

```
subtitleSettings: {}
```

### Season Playlist

```
seasonPlaylist: {
  seasons: [1], // Array of number
  getEpisode: (season, page, callback) => {
    // Calling api here and use callback in response
    callback({
      alias: "",
      duration: 0,
      link: "",
      part: 0,
      season: 0,
      thumbnail: "",
      title: null,
    });
  },
}
```

### Vote 

```
vote: {
  submitVote: ({ likeStatus, callback }) => {
    return { likeStatus, callback };
  }, // LikeStatus 1 equals to liked and 2 equals to disliked
  from: null,
  to: null,
  position: "bottom-right",
  offsetH: 46,
  offsetV: 167,
}
```

### Marker
Marker on progress bar 

```
markers: {
  markerTip: {
    display: false,
    skip: true,
  },
  onMarkerReached: (marker, index) => {
    console.log(marker, index);
  },
  onMarkerSkipZone: (marker, index) => {
    console.log("onMarkerSkipZone", marker, index);
  },
  markers: [{ time: null, duration: null }],
}

```

### Quality Selector
Default ranges for quality are:

```
qualitySelector: {
  qualities: [
    {
      quality: 144,
      label: 'UltraLow'
    },
    {
      quality: 240,
      label: 'VeryLow'
    },
    {
      quality: 360,
      label: 'Low'
    },
    {
      quality: 480,
      label: 'Medium'
    },
    {
      quality: 570,
      label: 'High'
    },
    {
      quality: 720,
      label: 'VeryHigh',
      symbol: 'HD'
    },
    {
      quality: 1080,
      label: 'UltraHigh',
      symbol: 'FHD'
    },
    {
      quality: 1440,
      label: 'Excellent',
      symbol: 'QHD'
    },
    {
      quality: 2304,
      label: 'VeryExcellent',
      symbol: 'UHD'
    }
  ],
}
```
### Collect Data

```
collectData: {
  token: "",
}
```