<commit_before>import { parser, creator } from "winamp-eqf";
import {
  genArrayBufferFromFileReference,
  genArrayBufferFromUrl,
  promptForFileReferences,
  genMediaDuration,
  genMediaTags
} from "./fileUtils";
import skinParser from "./skinParser";
import { BANDS, TRACK_HEIGHT, LOAD_STYLE } from "./constants";
import {
  getEqfData,
  nextTrack,
  getScrollOffset,
  getOverflowTrackCount,
  getPlaylistURL,
  getSelectedTrackObjects,
  getTracks,
  getTrackIsVisibleFunction,
  getWindowGraph,
  getWindowPositions,
  getWindowSizes
} from "./selectors";

import {
  clamp,
  base64FromArrayBuffer,
  downloadURI,
  normalize,
  sort,
  uniqueId,
  objectMap
} from "./utils";
import {
  CLOSE_WINAMP,
  ADD_TRACK_FROM_URL,
  SEEK_TO_PERCENT_COMPLETE,
  SET_BALANCE,
  SET_BAND_VALUE,
  SET_SKIN_DATA,
  SET_VOLUME,
  STOP,
  TOGGLE_REPEAT,
  TOGGLE_SHUFFLE,
  SET_EQ_ON,
  SET_EQ_OFF,
  TOGGLE_EQUALIZER_SHADE_MODE,
  CLOSE_EQUALIZER_WINDOW,
  REMOVE_TRACKS,
  REMOVE_ALL_TRACKS,
  PLAY,
  PAUSE,
  REVERSE_LIST,
  RANDOMIZE_LIST,
  SET_TRACK_ORDER,
  TOGGLE_VISUALIZER_STYLE,
  PLAY_TRACK,
  BUFFER_TRACK,
  SET_PLAYLIST_SCROLL_POSITION,
  DRAG_SELECTED,
  SET_MEDIA_TAGS,
  SET_MEDIA_DURATION,
  TOGGLE_MAIN_SHADE_MODE,
  TOGGLE_PLAYLIST_SHADE_MODE,
  MEDIA_TAG_REQUEST_INITIALIZED,
  MEDIA_TAG_REQUEST_FAILED,
  PLAYLIST_SIZE_CHANGED,
  UPDATE_WINDOW_POSITIONS,
  TOGGLE_DOUBLESIZE_MODE
} from "./actionTypes";

import LoadQueue from "./loadQueue";
import { getPositionDiff } from "./resizeUtils";
import { applyDiff } from "./snapUtils";

// Lower is better
const DURATION_VISIBLE_PRIORITY = 5;
const META_DATA_VISIBLE_PRIORITY = 10;
const DURATION_PRIORITY = 15;
const META_DATA_PRIORITY = 20;

const loadQueue = new LoadQueue({ threads: 4 });

function playRandomTrack() {
  return (dispatch, getState) => {
    const {
      playlist: { trackOrder, currentTrack }
    } = getState();
    if (trackOrder.length === 0) {
      return;
    }
    let nextId;
    do {
      nextId = trackOrder[Math.floor(trackOrder.length * Math.random())];
    } while (nextId === currentTrack && trackOrder.length > 1);
    // TODO: Sigh... Technically, we should detect if we are looping only repeat if we are.
    // I think this would require pre-computing the "random" order of a playlist.
    dispatch({ type: PLAY_TRACK, id: nextId });
  };
}

export function play() {
  return (dispatch, getState) => {
    const state = getState();
    if (
      state.media.status === "STOPPED" &&
      state.playlist.curentTrack == null &&
      state.playlist.trackOrder.length === 0
    ) {
      dispatch(openMediaFileDialog());
    } else {
      dispatch({ type: PLAY });
    }
  };
}

export function pause() {
  return (dispatch, getState) => {
    const { status } = getState().media;
    dispatch({ type: status === "PLAYING" ? PAUSE : PLAY });
  };
}

export function stop() {
  return { type: STOP };
}

export function nextN(n) {
  return (dispatch, getState) => {
    const state = getState();
    if (state.media.shuffle) {
      dispatch(playRandomTrack());
      return;
    }
    const nextTrackId = nextTrack(state, n);
    if (nextTrackId == null) {
      return;
    }
    dispatch({ type: PLAY_TRACK, id: nextTrackId });
  };
}

export function next() {
  return nextN(1);
}

export function previous() {
  return nextN(-1);
}

export function seekForward(seconds) {
  return function(dispatch, getState) {
    const { media } = getState();
    const { timeElapsed, length } = media;
    const newTimeElapsed = timeElapsed + seconds;
    const newPercentComplete = newTimeElapsed / length;
    dispatch({ type: SEEK_TO_PERCENT_COMPLETE, percent: newPercentComplete });
  };
}

export function seekBackward(seconds) {
  return seekForward(-seconds);
}

export function close() {
  return dispatch => {
    dispatch({ type: STOP });
    dispatch({ type: CLOSE_WINAMP });
  };
}

export function setVolume(volume) {
  return {
    type: SET_VOLUME,<commit_msg>Fix seek forward<commit_after>import { parser, creator } from "winamp-eqf";
import {
  genArrayBufferFromFileReference,
  genArrayBufferFromUrl,
  promptForFileReferences,
  genMediaDuration,
  genMediaTags
} from "./fileUtils";
import skinParser from "./skinParser";
import { BANDS, TRACK_HEIGHT, LOAD_STYLE } from "./constants";
import {
  getEqfData,
  nextTrack,
  getScrollOffset,
  getOverflowTrackCount,
  getPlaylistURL,
  getSelectedTrackObjects,
  getTracks,
  getTrackIsVisibleFunction,
  getWindowGraph,
  getWindowPositions,
  getWindowSizes
} from "./selectors";

import {
  clamp,
  base64FromArrayBuffer,
  downloadURI,
  normalize,
  sort,
  uniqueId,
  objectMap
} from "./utils";
import {
  CLOSE_WINAMP,
  ADD_TRACK_FROM_URL,
  SEEK_TO_PERCENT_COMPLETE,
  SET_BALANCE,
  SET_BAND_VALUE,
  SET_SKIN_DATA,
  SET_VOLUME,
  STOP,
  TOGGLE_REPEAT,
  TOGGLE_SHUFFLE,
  SET_EQ_ON,
  SET_EQ_OFF,
  TOGGLE_EQUALIZER_SHADE_MODE,
  CLOSE_EQUALIZER_WINDOW,
  REMOVE_TRACKS,
  REMOVE_ALL_TRACKS,
  PLAY,
  PAUSE,
  REVERSE_LIST,
  RANDOMIZE_LIST,
  SET_TRACK_ORDER,
  TOGGLE_VISUALIZER_STYLE,
  PLAY_TRACK,
  BUFFER_TRACK,
  SET_PLAYLIST_SCROLL_POSITION,
  DRAG_SELECTED,
  SET_MEDIA_TAGS,
  SET_MEDIA_DURATION,
  TOGGLE_MAIN_SHADE_MODE,
  TOGGLE_PLAYLIST_SHADE_MODE,
  MEDIA_TAG_REQUEST_INITIALIZED,
  MEDIA_TAG_REQUEST_FAILED,
  PLAYLIST_SIZE_CHANGED,
  UPDATE_WINDOW_POSITIONS,
  TOGGLE_DOUBLESIZE_MODE
} from "./actionTypes";

import LoadQueue from "./loadQueue";
import { getPositionDiff } from "./resizeUtils";
import { applyDiff } from "./snapUtils";

// Lower is better
const DURATION_VISIBLE_PRIORITY = 5;
const META_DATA_VISIBLE_PRIORITY = 10;
const DURATION_PRIORITY = 15;
const META_DATA_PRIORITY = 20;

const loadQueue = new LoadQueue({ threads: 4 });

function playRandomTrack() {
  return (dispatch, getState) => {
    const {
      playlist: { trackOrder, currentTrack }
    } = getState();
    if (trackOrder.length === 0) {
      return;
    }
    let nextId;
    do {
      nextId = trackOrder[Math.floor(trackOrder.length * Math.random())];
    } while (nextId === currentTrack && trackOrder.length > 1);
    // TODO: Sigh... Technically, we should detect if we are looping only repeat if we are.
    // I think this would require pre-computing the "random" order of a playlist.
    dispatch({ type: PLAY_TRACK, id: nextId });
  };
}

export function play() {
  return (dispatch, getState) => {
    const state = getState();
    if (
      state.media.status === "STOPPED" &&
      state.playlist.curentTrack == null &&
      state.playlist.trackOrder.length === 0
    ) {
      dispatch(openMediaFileDialog());
    } else {
      dispatch({ type: PLAY });
    }
  };
}

export function pause() {
  return (dispatch, getState) => {
    const { status } = getState().media;
    dispatch({ type: status === "PLAYING" ? PAUSE : PLAY });
  };
}

export function stop() {
  return { type: STOP };
}

export function nextN(n) {
  return (dispatch, getState) => {
    const state = getState();
    if (state.media.shuffle) {
      dispatch(playRandomTrack());
      return;
    }
    const nextTrackId = nextTrack(state, n);
    if (nextTrackId == null) {
      return;
    }
    dispatch({ type: PLAY_TRACK, id: nextTrackId });
  };
}

export function next() {
  return nextN(1);
}

export function previous() {
  return nextN(-1);
}

export function seekForward(seconds) {
  return function(dispatch, getState) {
    const { timeElapsed, length } = getState().media;
    const newTimeElapsed = timeElapsed + seconds;
    dispatch({
      type: SEEK_TO_PERCENT_COMPLETE,
      percent: newTimeElapsed / length * 100
    });
  };
}

export function seekBackward(seconds) {
  return seekForward(-seconds);
}

export function close() {
  return dispatch => {
    dispatch({ type: STOP });
    dispatch({ type: CLOSE_WINAMP });
  };
}

export function setVolume(volume) {
  return {
    type: SET_VOLUME,
{'fraction_non_alphanumeric': 0.1127867190470156, 'fraction_numerical': 0.004181979470282601, 'mean_word_length': 3.737094837935174, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '4851902', 'n_tokens_mistral': 2818, 'n_tokens_neox': 2752, 'n_words': 598}