<commit_before>import React from 'react';
import cn from 'classnames';
import keyboardJS from 'keyboardjs';
import ReactPlayer from 'react-player';

import AudioCtrl from '../client-lib/audio-ctrl';
import formatTime from '../client-lib/format-time';
import sendToAddon from '../client-lib/send-to-addon';
import sendMetricsEvent from '../client-lib/send-metrics-event';

import Queues from './queues';
import ErrorView from './error-view';
import ReplayView from './replay-view';
import PrevTrackBtn from './prev-button';
import NextTrackBtn from './next-button';
import PlayerControls from './player-controls';
import GeneralControls from './general-controls';
import MinimizedControls from './minimized-controls';

export default class Player extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      hovered: false, progress: 0, exited: false,
      showQueue: false, historyIndex: 0,
      time: '0:00 / 0:00', errorCount: 0,
      notificationCount: 0, wasMinimized: false
    };

    if (this.props.queue[0].player === 'audio') this.loadAudio();
    else this.unLoadAudio();
  }

  componentDidMount() {
    this.attachKeyboardShortcuts();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.queue[0].url !== this.props.queue[0].url) {
      if (this.props.queue[0].player === 'audio') this.loadAudio();
      else this.unLoadAudio();
    }
  }

  componentWillUnmount() {
    this.unLoadAudio();
  }

  loadAudio() {
    clearTimeout(this.loadingTimeout);
    this.loadingTimeout = setTimeout(() => {
      console.error('ERROR: loading timeout'); // eslint-disable-line no-console
    }, 30000);

    if (this.audio) this.audio.remove();

    this.audio = new AudioCtrl(Object.assign({}, this.props, {
      muted: this.props.muted,
      playing: this.props.playing,
      url: this.props.queue[0].url,
      time: this.props.queue[0].currentTime,
      onError: () => {
        const q = window.AppData.queue.slice();
        q[0].error = true;
        window.AppData.set({loaded: true, queue: JSON.stringify(q)});
      },
      onEnded: this.onEnded.bind(this),
      onLoaded: this.onLoaded.bind(this),
      onProgress: this.onProgress.bind(this),
      container: this.audioContainer
    }));
  }

  unLoadAudio() {
    if (this.audio) {
      this.audio.remove();
      delete this.audio;
      delete this.audioContainer;
    }
  }

  enterPlayer() {
    this.setState({hovered: true});
  }

  leavePlayer() {
    this.setState({hovered: false});
  }

  onPlay() {
    sendMetricsEvent('player_view', 'play', this.props.queue[0].domain);
    window.AppData.set({playing: true});
  }

  onPause() {
    sendMetricsEvent('player_view', 'pause'), this.props.queue[0].domain;
    window.AppData.set({playing: false});
  }

  handleVideoClick(ev) {
    ev.persist();
    if (this.props.exited) return;
    if ((ev.target.tagName !== 'VIDEO') && (ev.target.tagName !== 'CANVAS')) return;

    if (this.props.playing) {
      this.onPause();
      if (this.audio) this.audio.pause();
    } else {
      this.onPlay();
      if (this.audio) this.audio.play();
    }
  }

  onError() {
    window.AppData.set({error: true});
  }

  onEnded() {
    if (this.props.queue.length === 1) {
      window.AppData.set({exited: true});
    } else {
      // Force a render before we get the update response from
      // 'track-ended' event. This is to prevent a bug where
      // duplicates in the playlist get into a paused state. Bug #766
      const queue = window.AppData.queue.concat();
      queue.unshift({<commit_msg>Fix metrics logging for pause event (#1079)<commit_after>import React from 'react';
import cn from 'classnames';
import keyboardJS from 'keyboardjs';
import ReactPlayer from 'react-player';

import AudioCtrl from '../client-lib/audio-ctrl';
import formatTime from '../client-lib/format-time';
import sendToAddon from '../client-lib/send-to-addon';
import sendMetricsEvent from '../client-lib/send-metrics-event';

import Queues from './queues';
import ErrorView from './error-view';
import ReplayView from './replay-view';
import PrevTrackBtn from './prev-button';
import NextTrackBtn from './next-button';
import PlayerControls from './player-controls';
import GeneralControls from './general-controls';
import MinimizedControls from './minimized-controls';

export default class Player extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      hovered: false, progress: 0, exited: false,
      showQueue: false, historyIndex: 0,
      time: '0:00 / 0:00', errorCount: 0,
      notificationCount: 0, wasMinimized: false
    };

    if (this.props.queue[0].player === 'audio') this.loadAudio();
    else this.unLoadAudio();
  }

  componentDidMount() {
    this.attachKeyboardShortcuts();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.queue[0].url !== this.props.queue[0].url) {
      if (this.props.queue[0].player === 'audio') this.loadAudio();
      else this.unLoadAudio();
    }
  }

  componentWillUnmount() {
    this.unLoadAudio();
  }

  loadAudio() {
    clearTimeout(this.loadingTimeout);
    this.loadingTimeout = setTimeout(() => {
      console.error('ERROR: loading timeout'); // eslint-disable-line no-console
    }, 30000);

    if (this.audio) this.audio.remove();

    this.audio = new AudioCtrl(Object.assign({}, this.props, {
      muted: this.props.muted,
      playing: this.props.playing,
      url: this.props.queue[0].url,
      time: this.props.queue[0].currentTime,
      onError: () => {
        const q = window.AppData.queue.slice();
        q[0].error = true;
        window.AppData.set({loaded: true, queue: JSON.stringify(q)});
      },
      onEnded: this.onEnded.bind(this),
      onLoaded: this.onLoaded.bind(this),
      onProgress: this.onProgress.bind(this),
      container: this.audioContainer
    }));
  }

  unLoadAudio() {
    if (this.audio) {
      this.audio.remove();
      delete this.audio;
      delete this.audioContainer;
    }
  }

  enterPlayer() {
    this.setState({hovered: true});
  }

  leavePlayer() {
    this.setState({hovered: false});
  }

  onPlay() {
    sendMetricsEvent('player_view', 'play', this.props.queue[0].domain);
    window.AppData.set({playing: true});
  }

  onPause() {
    sendMetricsEvent('player_view', 'pause', this.props.queue[0].domain);
    window.AppData.set({playing: false});
  }

  handleVideoClick(ev) {
    ev.persist();
    if (this.props.exited) return;
    if ((ev.target.tagName !== 'VIDEO') && (ev.target.tagName !== 'CANVAS')) return;

    if (this.props.playing) {
      this.onPause();
      if (this.audio) this.audio.pause();
    } else {
      this.onPlay();
      if (this.audio) this.audio.play();
    }
  }

  onError() {
    window.AppData.set({error: true});
  }

  onEnded() {
    if (this.props.queue.length === 1) {
      window.AppData.set({exited: true});
    } else {
      // Force a render before we get the update response from
      // 'track-ended' event. This is to prevent a bug where
      // duplicates in the playlist get into a paused state. Bug #766
      const queue = window.AppData.queue.concat();
      queue.unshift({
{'fraction_non_alphanumeric': 0.1563195991091314, 'fraction_numerical': 0.008351893095768375, 'mean_word_length': 3.08470722001137, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4991952', 'n_tokens_mistral': 2329, 'n_tokens_neox': 2262, 'n_words': 501}