<commit_before>import { OnInit } from '@angular/core';
import { Component, Input, HostListener } from '@angular/core';
import { Router, NavigationStart, Event } from '@angular/router';

/* WaveSurfer NPM headers */
import * as WaveSurfer from 'wavesurfer.js';
import * as Region from 'wavesurfer.js/dist/plugin/wavesurfer.regions';
import * as RegionsPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.regions';
import * as TimelinePlugin from 'wavesurfer.js/dist/plugin/wavesurfer.timeline';
import * as MinimapPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.minimap';

import { AnnotatorService } from '../shared/annotator.service';
import { Annotation } from '../shared/annotator.service';

import { MatDialog } from '@angular/material';
import { Dialog } from '../dialog/dialog.component';

const BASE_COLOUR = 'rgba(0, 100, 0, 0.2)';
const SELECTED_COLOUR = 'rgba(0, 200, 200, 0.2)';

@Component({
  selector: 'player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.css'],
})
export class PlayerComponent implements OnInit {
  player: any = null;
  @Input() clip: any;
  @Input() annotations: any;

  annotatorSubscription: any = null;

  selectedRegion: any = null;

  ready: boolean = null;

  private zoom: number;
  private zoom_threshold = 10;

  constructor(
    private dialog: MatDialog,
    private annotatorService: AnnotatorService,
    private router: Router) {
    router.events.subscribe( (event: Event) => {
      if (event instanceof NavigationStart) {
        this.player.destroy();
        this.annotatorSubscription.unsubscribe();
      }
    });

    this.annotatorSubscription = this.annotatorService.annotationsEvent.subscribe((event) => {
      if (event.type === 'rebuild') {
        this.player.clearRegions();
        this.annotations = this.annotatorService.getAnnotations();
        this.loadRegions();
      }
      else if (event.type === 'resize') {
        this.setHeight(event.newSize);
      }
      else if (event.type === 'selectAnnotation') {
        if (event.new !== null) {
          const newRegion = this.findRegion(event.new.id);
          this.selectRegion(newRegion, false);
        }
      }
    });
  }

  play(): void {
    this.player.play();
  }

  stop(): void {
    if (this.player.getCurrentTime() === this.player.getDuration()) {
      // Reset to beginning only if we're at the end and not a region end
      this.player.stop();
    }
  }

  pause(): void {
    this.player.pause();
  }

  seek(position: number): void {
    this.player.seekTo(0);
    this.player.skip(position);
  }

  getPos(): number {
    return Math.floor(this.player.getCurrentTime());
  }

  getDuration(): number {
    return Math.floor(this.player.getDuration());
  }

  loadRegions(): void {
    if (this.player.handlers !== null) { // Hackish fix to stop wrapper.null implosions
      for (const annotation of this.annotations) {
        this.player.addRegion({
          id: annotation.id,
          start: annotation.start,
          end: annotation.end,
          color: BASE_COLOUR,
        });
      }
    }

    if (this.annotations.length > 0) {
      this.selectRegion(this.findRegion(this.annotations[0].id), false)
    }
  }

  public setHeight(pixels: number) {
    this.player.drawer.setHeight(pixels);
    this.player.params.height = pixels;
    this.player.empty();
    this.player.drawBuffer();
  }

  ngOnInit(): void {
    this.zoom = 3;
    this.player = WaveSurfer.create({
      container: '#waveform',
      waveColor: 'black',
      progressColor: 'white',
      controls: true,
      barHeight: 20,
      plugins: [
        MinimapPlugin.create(),
        RegionsPlugin.create(),
        TimelinePlugin.create({
          container: '#timeline'
        }),
      ]
    });

    this.player.loadArrayBuffer(this.clip.slice(0));
    /*
    var slider = document.querySelector('[data-action="zoom"]');
    slider.addEventListener('input', () => {
      var value = (slider as HTMLInputElement).value;
      this.player.zoom(Number(value));
    });
     */

    this.player.on('ready', () => {
      this.loadRegions();
      this.player.zoom(this.zoom);
      this.player.enableDragSelection({
          color: BASE_COLOUR,
      });

      this.setHeight(120);

      this.ready = true;
      // (slider as HTMLInputElement).value = this.player.params.minPxPerSec;
    });

    /* Move cursor to beginning of region */
    this.player.on('region-click', (region: Region, e: any) => {
      e.stopPropagation(); // Stop click from being overridden by mousepos
      this.selectRegion(region);
    });

    this.player.on('region-update-end', (region: Region) => {
      if (this.ready === true) {
        const annotation = this.annotatorService.getAnnotationByID(region.id)

        annotation.start = region.start;
        annotation.end = region.end;

        this.selectRegion(region);
      }
    });

    this.player.on('region-created', (region: Region) => {
      if (this.ready === true) {
        if (region.id.startsWith('wavesurfer_')) {
          this.annotatorService.createAnnotationFromSegment(
            {
              'id': region.id,
              'start': region.start,
              'end': region.end
            });
        }
      }
    });

    this.player.on('finish', () => {
      this.stop();
    });

    // Forces Angular to update component every second
    setInterval(() => {}, 1000);
  }

  zoomIn() {
    if (this.zoom < this.zoom_threshold) {<commit_msg>Fixed ordering/premature annotation creation on drag, refactor<commit_after>import { OnInit } from '@angular/core';
import { Component, Input, HostListener } from '@angular/core';
import { Router, NavigationStart, Event } from '@angular/router';

/* WaveSurfer NPM headers */
import * as WaveSurfer from 'wavesurfer.js';
import * as Region from 'wavesurfer.js/dist/plugin/wavesurfer.regions';
import * as RegionsPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.regions';
import * as TimelinePlugin from 'wavesurfer.js/dist/plugin/wavesurfer.timeline';
import * as MinimapPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.minimap';

import { AnnotatorService } from '../shared/annotator.service';
import { Annotation } from '../shared/annotator.service';

import { MatDialog } from '@angular/material';
import { Dialog } from '../dialog/dialog.component';

const BASE_COLOUR = 'rgba(0, 100, 0, 0.2)';
const SELECTED_COLOUR = 'rgba(0, 200, 200, 0.2)';

@Component({
  selector: 'player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.css'],
})
export class PlayerComponent implements OnInit {
  player: WaveSurfer = null;
  @Input() clip: any;
  annotations: Array<any> = null;

  annotatorSubscription: any = null;

  selectedRegion: any = null;

  ready: boolean = null;

  private zoom: number;
  private zoom_threshold = 10;

  constructor(
    private dialog: MatDialog,
    private annotatorService: AnnotatorService,
    private router: Router) {
  }

  ngOnInit(): void {
    this.annotations = this.annotatorService.getAnnotations();
    this.router.events.subscribe( (event: Event) => {
      if (event instanceof NavigationStart) {
        this.player.destroy();
        this.annotatorSubscription.unsubscribe();
      }
    });
    this.annotatorSubscription = this.annotatorService.annotationsEvent.subscribe((event) => {
      if (event.type === 'rebuild') {
        this.player.clearRegions();
        this.annotations = this.annotatorService.getAnnotations();
        this.loadRegions();
      }
      else if (event.type === 'resize') {
        this.setHeight(event.newSize);
      }
      else if (event.type === 'selectAnnotation') {
        if (event.new !== null) {
          const newRegion = this.findRegion(event.new.id);
          this.selectRegion(newRegion, false);
        }
      }
    });

    this.zoom = 3;
    this.player = WaveSurfer.create({
      container: '#waveform',
      waveColor: 'black',
      progressColor: 'white',
      controls: true,
      barHeight: 20,
      plugins: [
        MinimapPlugin.create(),
        RegionsPlugin.create(),
        TimelinePlugin.create({
          container: '#timeline'
        }),
      ]
    });

    this.player.loadArrayBuffer(this.clip);

    this.player.on('ready', () => {
      this.loadRegions();
      this.player.zoom(this.zoom);
      this.player.enableDragSelection({
          color: BASE_COLOUR,
      });

      this.setHeight(120);

      this.ready = true;
    });

    /* Move cursor to beginning of region */
    this.player.on('region-click', (region: Region, e: any) => {
      e.stopPropagation(); // Stop click from being overridden by mousepos
      this.selectRegion(region);
    });

    this.player.on('region-update-end', (region: Region) => {
      if (this.ready === true) {
        const annotation = this.annotatorService.getAnnotationByID(region.id)

        if (annotation !== null) {
          annotation.start = region.start;
          annotation.end = region.end;

          this.selectRegion(region);
        }
      }
    });

    this.player.on('region-created', (region: Region) => {
      if (this.ready === true) {
        if (region.id.startsWith('wavesurfer_')) {
          const createFinish = this.player.on('region-update-end', 
            (region: Region) => {
              this.annotatorService.createAnnotationFromSegment(
                {
                  'id': region.id,
                  'start': region.start,
                  'end': region.end
                }
              );
              // You'd think this would work, but it doesn't: createFinish.un();
              // So instead we do a slightly more roundabout approach.
              this.player.un(createFinish.name, createFinish.callback);
            }
          );
        }
      }
    });

    this.player.on('finish', () => {
      this.stop();
    });

    setInterval(() => {}, 100);
  }


  play(): void {
    this.player.play();
  }

  stop(): void {
    if (this.player.getCurrentTime() === this.player.getDuration()) {
      // Reset to beginning only if we're at the end and not a region end
      this.player.stop();
    }
  }

  pause(): void {
    this.player.pause();
  }

  seek(position: number): void {
    this.player.seekTo(0);
    this.player.skip(position);
  }

  getPos(): number {
    return Math.floor(this.player.getCurrentTime());
  }

  getDuration(): number {
    return Math.floor(this.player.getDuration());
  }

  loadRegions(): void {
    if (this.player.handlers !== null) { // Hackish fix to stop wrapper.null implosions
      for (const annotation of this.annotations) {
        this.player.addRegion({
          id: annotation.id,
          start: annotation.start,
          end: annotation.end,
          color: BASE_COLOUR,
        });
      }
    }

    if (this.annotations.length > 0) {
      this.selectRegion(this.findRegion(this.annotations[0].id), false)
    }
  }

  public setHeight(pixels: number) {
    this.player.drawer.setHeight(pixels);
    this.player.params.height = pixels;
    this.player.empty();
    this.player.drawBuffer();
  }

  zoomIn() {
    if (this.zoom < this.zoom_threshold) {
{'fraction_non_alphanumeric': 0.14353510028653296, 'fraction_numerical': 0.005551575931232092, 'mean_word_length': 2.571794051806844, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 24, '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': '1750919', 'n_tokens_mistral': 3493, 'n_tokens_neox': 3319, 'n_words': 695}