Как сделать так, чтобы игрок Musi c на базе Howler. js хорошо работал при запросе быстрого поиска с помощью колесика мыши? - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть следующий класс PlaylistItem, который, кажется, не работает. Проблемными функциями c являются step и seekBackOrForward. seekBackOrForward вызывается, когда пользователь прокручивает элемент HTML, представляющий игрока musi c. Когда пользователь выполняет прокрутку в секунду, он работает хорошо. Когда он делает больше прокруток в секунду, игрок показывает 0:00 как текущее время в течение небольшого времени или пока я не прокручиваю снова, на этот раз медленно.

export class PlaylistItem {
    title: ko.Observable<string>;
    file: ko.Observable<string>;
    formattedDuration: ko.Computed<string>;

    /**
     * In seconds.
     */
    duration: ko.Observable<number>;
    isPlaying: ko.Observable<boolean>;
    lastPosition: ko.Observable<number>;

    howl: Howl;
    saveSeek: number;
    musicID: number | null;

    state: ko.Observable<MusicPlayerState>;

    audioFolderPath: string;

    wave: any;

    timerString: ko.Observable<string>;
    timerPercent: ko.Observable<string>;

    animation: number | null;

    constructor(t: string, f: string, d: number, wave: any) {
        this.title = ko.observable(t);
        this.file = ko.observable(f);
        this.duration = ko.observable(d);
        this.isPlaying = ko.observable(false);
        this.lastPosition = ko.observable(0);
        this.state = ko.observable(MusicPlayerState.Startup);
        this.wave = wave;

        this.formattedDuration = ko.computed(() => {
            return Utils.formatTime(Math.round(this.duration()));
        });

        this.howl = null;

        this.timerString = ko.observable("0:00");
        this.timerPercent = ko.observable("0%");

        this.audioFolderPath = "/wp-content/themes/custom-theme/assets/audio";

        this.animation = null;

        this.saveSeek = 0;
        this.musicID = null;
    }

    unpause() : void
    {
        if (this.howl === null)
        {
            return;
        }

        this.howl.play(this.musicID);
        this.howl.seek(this.saveSeek, this.musicID);

        this.isPlaying(true);
        this.state(MusicPlayerState.Playing);
    }

    pause() : void
    {
        if (this.howl === null)
        {
            return;
        }

        this.howl.pause();

        this.saveSeek = this.howl.seek(this.musicID);

        this.state(MusicPlayerState.Paused);
    }

    play() : void
    {
        let bar: HTMLElement = document.getElementById('bar');
        let pauseBtn: HTMLElement = document.getElementById('pauseBtn');
        let loading: HTMLElement = document.getElementById('loading');

        let self = this;

        this.howl = new Howl({
            src: [`${this.audioFolderPath}/${this.file()}.webm`,
                    `${this.audioFolderPath}/${this.file()}.mp3`],
            html5: true, // Force to HTML5 so that the audio can stream in (best for large files).
            onplay: () : void =>
            {
                // Start updating the progress of the track.
                if (self.animation != null)
                {
                  cancelAnimationFrame(self.animation);
                  self.animation = null;
                }
                self.animation = requestAnimationFrame(self.step.bind(self));

                // Start the wave animation if we have already loaded
                self.wave.container.style.display = 'block';
                bar.style.display = 'none';
                pauseBtn.style.display = 'block';
            },
            onload: () : void =>
            {
                // Start the wave animation.
                self.wave.container.style.display = 'block';
                bar.style.display = 'none';
                loading.style.display = 'none';
            },
            onend:  () : void =>
            {
              // Stop the wave animation.
              self.wave.container.style.display = 'none';
              bar.style.display = 'block';
              self.state(MusicPlayerState.Playing);

              self.howl.play(self.musicID);
            },
            onpause:  () : void =>
            {
              // Stop the wave animation.
              self.wave.container.style.display = 'none';
              bar.style.display = 'block';
            },
            onstop:  () : void =>
            {
              // Stop the wave animation.
              self.wave.container.style.display = 'none';
              bar.style.display = 'block';
            },
            onseek:  () : void =>
            {
              if (self.animation != null)
              {
                cancelAnimationFrame(self.animation);
                self.animation = null;
              }
              // Start upating the progress of the track.
              self.animation = requestAnimationFrame(self.step.bind(self));
            }
        });

        // Begin playing the sound.
        self.musicID = self.howl.play();

        self.state(MusicPlayerState.Playing);
    }

  /**
   * The step called within requestAnimationFrame to update the playback position.
   */
  step(): void
  {
    // Get the Howl we want to manipulate.
    let sound: Howl | null = this.howl;

    // Determine our current seek position.
    let seek: number = <number>(sound.seek()) || 0; // TODO: what if it is a Howl?

    if (sound === null)
    {
      this.timerString(Utils.formatTime(0));
      this.timerPercent("0%");
    }
    else
    {
      this.timerString(Utils.formatTime(Math.round(seek)));
      this.timerPercent((((seek / sound.duration()) * 100) || 0) + '%');
    }

    // If the sound is still playing, continue stepping.
    if (sound.playing()) {
      this.animation = requestAnimationFrame(this.step.bind(this));
    }
  }

  /*
   * Scrolls back or forward in the current song, depending on the mouse wheel direction.
   * vm - the PageViewModel object.
   * e - the wheel event object.
   */
  seekBackOrForward(vm /* : PageViewModel */, e) : void
  {
    // the currently playing song
    let item : PlaylistItem = vm.player.currentPlaylistItem(); // wudl have been `this`

    // the song player object
    let h: Howl = item.howl;

    // if the song was not playing ever since the page loaded
    if (h === null || h === undefined)
    {
      // do nothing.
      return;
    }

    // get the position in the current song
    let s: number = /* item.saveSeek */ h.seek();






    // if (typeof s !== "number" || s < 2)
    // {
    //   console.log(s);
    //   return;
    // }






    // if scrolling towards the screen
    if (Math.sign(e.originalEvent.deltaY) === 1)
    {
      ++s;
    }
    // else if not scrolling towards the screen but in the oposite direction
    else
    {
      --s;
    }
    // seek to the next or previous second as chosen above
    h.seek(s, item.musicID);

    // save the new position for the case in which the melody is put on pause and the user unpauses later to this position
    item.saveSeek = s;
  }
}

(я знаю, что seekBackOrForward должен получить доступ к this не через метод, а через ключевое слово this, но для меня это мелочь, которую я могу изменить в будущем.)

Код основан на первом официальном Howler. js демо здесь ( Musi c Player ). При необходимости я могу опубликовать любой другой соответствующий фрагмент кода.

Я попытался воспроизвести проблему в этом JSFiddle , но там нет проблем.

Я использую TypeScript, Howler . js, нокаут. js и Firefox.

Спасибо.

...