<commit_before>import React, { Component } from 'react';
import { propTypes, defaultProps } from '../props';
import { contextTypes } from '../context';
import Hls from 'hls.js';
import FullScreenApi from '../utils/FullScreenApi';
import { isFunction, throttle } from '../utils';

const AUDIO_EXTENSIONS = /\.(mp3|wav)($|\?)/;
const HLS_EXTENSIONS = /\.(m3u8)($|\?)/;
const DECIMAL = 10;
const STATE_FRESH_INTERVAL = 300;
const EVENTS = [
  'onAbort',
  'onCanPlay',
  'onCanPlayThrough',
  'onDurationChange',
  'onEmptied',
  'onEncrypted',
  'onEnded',
  'onError',
  'onLoadedData',
  'onLoadedMetadata',
  'onLoadStart',
  'onPause',
  'onPlay',
  'onPlaying',
  'onProgress',
  'onRateChange',
  'onSeeked',
  'onSeeking',
  'onStalled',
  'onSuspend',
  'onTimeUpdate',
  'onVolumeChange',
  'onWaiting',
];

export default class Hydeo extends Component {

  static propTypes = propTypes;
  static defaultProps = defaultProps;
  static childContextTypes = contextTypes;

  constructor(props, ...args) {
    super(props, ...args);
    this.play = this.play.bind(this);
    this.pause = this.pause.bind(this);
    this.mute = this.mute.bind(this);
    this.unmute = this.unmute.bind(this);
    this.setVolume = this.setVolume.bind(this);
    this.requestFullScreen = this.requestFullScreen.bind(this);
    this.exitFullScreen = this.exitFullScreen.bind(this);
    this.toggleFullScreen = this.toggleFullScreen.bind(this);
    this.toggleVolume = this.toggleVolume.bind(this);
    this.togglePlay = this.togglePlay.bind(this);
    this.getMediaState = this.getMediaState.bind(this);
  }

  getChildContext() {
    return Object.assign({}, {
      play: this.play,
      pause: this.pause,
      togglePlay: this.togglePlay,
      mute: this.mute,
      unmute: this.unmute,
      setVolume: this.setVolume,
      toggleVolume: this.toggleVolume,
      requestFullScreen: this.requestFullScreen,
      exitFullScreen: this.exitFullScreen,
      toggleFullScreen: this.toggleFullScreen,
    }, this.state);
  }

  componentWillMount() {
    this.updateState = throttle(this.updateState, STATE_FRESH_INTERVAL).bind(this);

    this.mediaEventProps = EVENTS.reduce((eventMap, currentEvent) => {
      const eventProps = eventMap;
      eventProps[currentEvent] = (event) => {
        if (currentEvent in this.props && isFunction(this.props[currentEvent])) {
          this.props[currentEvent].call(event);
        }

        if (currentEvent in this && isFunction(this[currentEvent])) {
          this[currentEvent].call(this, event);
        }

        this.updateState();
      };
      return eventProps;
    }, {});
  }

  componentDidMount() {
    const media = this.refs.media;
    if (HLS_EXTENSIONS.test(this.props.src) && Hls.isSupported()) {
      const hls = new Hls({ defaultAudioCodec: 'avc1.42E01E, mp4a.40.2' });
      hls.loadSource(this.props.src);
      hls.attachMedia(media);
      // hls.on(Hls.Events.MANIFEST_PARSED, () => media.play());
    }

    FullScreenApi.onChange(this.refs.hydeo, () => {
      const isFullScreen = FullScreenApi.isFullScreen();
      this.setState({ isFullScreen });
    });

    this.props.onReady(Object.assign({}, this.getChildContext(), {
      getMediaState: this.getMediaState,
    }));
  }

  onTimeUpdate(event) {
    const cuepoints = this.props.cuepoints;
    if (!cuepoints) {
      return;
    }

    const currentTime = event.target.currentTime;
    const currentSecond = parseInt(currentTime, DECIMAL);
    cuepoints.forEach((item) => {
      const cuepoint = item;
      const start = parseInt(cuepoint.time, DECIMAL);
      if (currentSecond === start) {
        if (isFunction(cuepoint.onEnter) && !cuepoint.$$isDirty) {
          cuepoint.onEnter(this.currentTime, cuepoint.params);
        }
        cuepoint.$$isDirty = true;
      }

      if (currentSecond > start) {
        if (isFunction(cuepoint.onComplete)) {
          cuepoint.onComplete(this.currentTime, cuepoint.params);
        }
        cuepoint.$$isDirty = false;
      }

      if (currentSecond < start) {
        cuepoint.$$isDirty = false;
      }
    });
  }

  getMediaState() {
    return this.state;
  }

  setVolume(volume) {
    this.refs.media.volume = volume;
  }

  play() {
    this.refs.media.play();
  }

  pause() {
    this.refs.media.pause();
  }

  togglePlay() {
    if (this.state.paused) {
      this.play();
    } else {
      this.pause();
    }
  }

  mute() {
    this.refs.media.muted = true;
  }

  unmute() {
    this.refs.media.muted = false;
  }

  toggleVolume() {
    if (this.state.muted) {
      this.unmute();
    } else {
      this.mute();
    }
  }

  seek(time) {
    this.refs.media.currentTime = time;
  }

  requestFullScreen() {
    FullScreenApi.request(this.refs.hydeo);
    this.setState({ isFullScreen: true });
  }

  exitFullScreen() {
    FullScreenApi.exit();
    this.setState({ isFullScreen: false });
  }

  toggleFullScreen() {
    if (this.state.isFullScreen) {
      this.exitFullScreen();
    } else {
      this.requestFullScreen();
    }
  }

  updateState() {
    const media = this.refs.media;
    const duration = media.duration;
    const currentTime = media.currentTime;
    const buffered = media.buffered;

    this.setState({
      totalTime: duration,
      currentTime,
      buffered,
      paused: media.paused,
      muted: media.muted,
      volume: media.volume,
      percentageBuffered: buffered.length && buffered.end(buffered.length - 1) / duration * 100,
      percentagePlayed: currentTime / duration * 100,
    });
  }

  render() {
    const Media = AUDIO_EXTENSIONS.test(this.props.src) ? 'audio' : 'video';
    const mediaProps = Object.assign({}, this.props, this.mediaEventProps);

    return (
      <div ref="hydeo">
        <Media ref="media" { ...mediaProps } onClick={ this.togglePlay } />
        { this.props.children }
      </div>
    );
  }<commit_msg>fix: fix fullscreen change event<commit_after>import React, { Component } from 'react';
import { propTypes, defaultProps } from '../props';
import { contextTypes } from '../context';
import Hls from 'hls.js';
import FullScreenApi from '../utils/FullScreenApi';
import { isFunction, throttle } from '../utils';

const AUDIO_EXTENSIONS = /\.(mp3|wav)($|\?)/;
const HLS_EXTENSIONS = /\.(m3u8)($|\?)/;
const DECIMAL = 10;
const STATE_FRESH_INTERVAL = 300;
const EVENTS = [
  'onAbort',
  'onCanPlay',
  'onCanPlayThrough',
  'onDurationChange',
  'onEmptied',
  'onEncrypted',
  'onEnded',
  'onError',
  'onLoadedData',
  'onLoadedMetadata',
  'onLoadStart',
  'onPause',
  'onPlay',
  'onPlaying',
  'onProgress',
  'onRateChange',
  'onSeeked',
  'onSeeking',
  'onStalled',
  'onSuspend',
  'onTimeUpdate',
  'onVolumeChange',
  'onWaiting',
];

export default class Hydeo extends Component {

  static propTypes = propTypes;
  static defaultProps = defaultProps;
  static childContextTypes = contextTypes;

  constructor(props, ...args) {
    super(props, ...args);
    this.play = this.play.bind(this);
    this.pause = this.pause.bind(this);
    this.mute = this.mute.bind(this);
    this.unmute = this.unmute.bind(this);
    this.setVolume = this.setVolume.bind(this);
    this.requestFullScreen = this.requestFullScreen.bind(this);
    this.exitFullScreen = this.exitFullScreen.bind(this);
    this.toggleFullScreen = this.toggleFullScreen.bind(this);
    this.toggleVolume = this.toggleVolume.bind(this);
    this.togglePlay = this.togglePlay.bind(this);
    this.getMediaState = this.getMediaState.bind(this);
  }

  getChildContext() {
    return Object.assign({}, {
      play: this.play,
      pause: this.pause,
      togglePlay: this.togglePlay,
      mute: this.mute,
      unmute: this.unmute,
      setVolume: this.setVolume,
      toggleVolume: this.toggleVolume,
      requestFullScreen: this.requestFullScreen,
      exitFullScreen: this.exitFullScreen,
      toggleFullScreen: this.toggleFullScreen,
    }, this.state);
  }

  componentWillMount() {
    this.updateState = throttle(this.updateState, STATE_FRESH_INTERVAL).bind(this);

    this.mediaEventProps = EVENTS.reduce((eventMap, currentEvent) => {
      const eventProps = eventMap;
      eventProps[currentEvent] = (event) => {
        if (currentEvent in this.props && isFunction(this.props[currentEvent])) {
          this.props[currentEvent].call(event);
        }

        if (currentEvent in this && isFunction(this[currentEvent])) {
          this[currentEvent].call(this, event);
        }

        this.updateState();
      };
      return eventProps;
    }, {});
  }

  componentDidMount() {
    const media = this.refs.media;
    if (HLS_EXTENSIONS.test(this.props.src) && Hls.isSupported()) {
      const hls = new Hls({ defaultAudioCodec: 'avc1.42E01E, mp4a.40.2' });
      hls.loadSource(this.props.src);
      hls.attachMedia(media);
      // hls.on(Hls.Events.MANIFEST_PARSED, () => media.play());
    }

    FullScreenApi.onChange(this.refs.hydeo, () => {
      const isFullScreen = FullScreenApi.isFullScreen();
      this.updateState({ isFullScreen });
    });

    this.props.onReady(Object.assign({}, this.getChildContext(), {
      getMediaState: this.getMediaState,
    }));
  }

  onTimeUpdate(event) {
    const cuepoints = this.props.cuepoints;
    if (!cuepoints) {
      return;
    }

    const currentTime = event.target.currentTime;
    const currentSecond = parseInt(currentTime, DECIMAL);
    cuepoints.forEach((item) => {
      const cuepoint = item;
      const start = parseInt(cuepoint.time, DECIMAL);
      if (currentSecond === start) {
        if (isFunction(cuepoint.onEnter) && !cuepoint.$$isDirty) {
          cuepoint.onEnter(this.currentTime, cuepoint.params);
        }
        cuepoint.$$isDirty = true;
      }

      if (currentSecond > start) {
        if (isFunction(cuepoint.onComplete)) {
          cuepoint.onComplete(this.currentTime, cuepoint.params);
        }
        cuepoint.$$isDirty = false;
      }

      if (currentSecond < start) {
        cuepoint.$$isDirty = false;
      }
    });
  }

  getMediaState() {
    return this.state;
  }

  setVolume(volume) {
    this.refs.media.volume = volume;
  }

  play() {
    this.refs.media.play();
  }

  pause() {
    this.refs.media.pause();
  }

  togglePlay() {
    if (this.state.paused) {
      this.play();
    } else {
      this.pause();
    }
  }

  mute() {
    this.refs.media.muted = true;
  }

  unmute() {
    this.refs.media.muted = false;
  }

  toggleVolume() {
    if (this.state.muted) {
      this.unmute();
    } else {
      this.mute();
    }
  }

  seek(time) {
    this.refs.media.currentTime = time;
  }

  requestFullScreen() {
    FullScreenApi.request(this.refs.hydeo);
    this.setState({ isFullScreen: true });
  }

  exitFullScreen() {
    FullScreenApi.exit();
    this.setState({ isFullScreen: false });
  }

  toggleFullScreen() {
    if (this.state.isFullScreen) {
      this.exitFullScreen();
    } else {
      this.requestFullScreen();
    }
  }

  updateState(states) {
    const media = this.refs.media;
    const duration = media.duration;
    const currentTime = media.currentTime;
    const buffered = media.buffered;

    this.setState({
      ...states,
      totalTime: duration,
      currentTime,
      buffered,
      paused: media.paused,
      muted: media.muted,
      volume: media.volume,
      percentageBuffered: buffered.length && buffered.end(buffered.length - 1) / duration * 100,
      percentagePlayed: currentTime / duration * 100,
    });
  }

  render() {
    const Media = AUDIO_EXTENSIONS.test(this.props.src) ? 'audio' : 'video';
    const mediaProps = Object.assign({}, this.props, this.mediaEventProps);
    const mediaStyle = {
      width: '100%',
      height: '100%',
    };

    return (
      <div ref="hydeo">
        <Media style={ mediaStyle } ref="media" { ...mediaProps } onClick={ this.togglePlay } />
        { this.props.children }
      </div>
    );
  }
{'fraction_non_alphanumeric': 0.14543622470400538, 'fraction_numerical': 0.0045343857586699135, 'mean_word_length': 2.8209817131857555, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6506011', 'n_tokens_mistral': 4094, 'n_tokens_neox': 3915, 'n_words': 679}