<commit_before>import Inferno from 'inferno';
import Component from 'inferno-component';
import { knuthShuffle } from 'knuth-shuffle';
import store from 'store';
import expirePlugin from 'store/plugins/expire';
import Dashboard from './Dashboard.jsx';
import Player from './Player.jsx';
import api from './utilities/api.js';
import help from './utilities/helpers.js';
import '../scss/App.scss';

const STORE_POPULAR = 'popular';
const STORE_PLAYED = 'played';
const STORE_POPULAR_EXPIRY = help.daysFromNow(7);
const STORE_TAGS_EXPIRY = help.daysFromNow(7);
const STORE_PLAYED_LIMIT = 500; // TODO
const PLAYLISTS_LIMIT = 10;

export default class App extends Component {
  constructor() {
    super();

    store.addPlugin(expirePlugin);

    this.state = {
      currentTags: [],
      playlist: false,
      playlistLoading: false,
      track: false,
      topTags: store.get(STORE_POPULAR) || [],
      relatedTags: [],
    };

    this.played = store.get(STORE_PLAYED) || [];

    this.addTag = this.addTag.bind(this);
    this.removeTag = this.removeTag.bind(this);
    this.fetchPlaylists = this.fetchPlaylists.bind(this);
    this.fetchNextSong = this.fetchNextSong.bind(this);

    if (!this.state.topTags.length) this.fetchTopTags();
  }

  fetchTopTags() {
    api.explore({ page: 1, per_page: 30 }).then(res => {
      const tags = [...this.state.topTags, ...res.filters];
      this.setState({ topTags: tags });
      store.set(STORE_POPULAR, tags, STORE_POPULAR_EXPIRY);
    });
  }

  addTag(tag) {
    const oldTag = this.state.currentTags[0];
    const newTags = !oldTag || tag === oldTag ? [tag] : [tag, oldTag];
    this.setState({ currentTags: newTags });
    this.fetchPlaylists({ tags: newTags });
  }

  removeTag(tag) {
    const index = this.state.currentTags.indexOf(tag);
    this.state.currentTags.splice(index, 1);
    this.setState({ currentTags: this.state.currentTags });
    return this.state.currentTags;
  }

  mapPlaylists(playlists) {
    return knuthShuffle(playlists).map(playlist => {
      return {
        id: playlist.id,
        colors: playlist.color_palette,
        cover: playlist.cover_urls.sq500,
      };
    });
  }

  mapRelatedTags(tags) {
    return tags.map(tag => {
      return {
        name: tag.name,
        image: tag.artist_avatar,
      }
    });
  }

  validPlaylist(playlist) {
    if (playlist) {
      const alreadyPlayed = this.played.indexOf(playlist.id) >= 0;
      if (alreadyPlayed) this.fetchPlaylists();
      else return true;
    } else {
      const removableTags = this.state.currentTags.length > 1;
      if (removableTags) this.fetchPlaylists({ tags: this.removeTag(1) });
    }

    return false;
  }

  loadPlaylist(tagString, data) {
    const playlist = data.playlists[data.index];
    if (!this.validPlaylist(playlist)) return false
    this.setState({ playlist: playlist, relatedTags: data.related });
    this.fetchNextSong(playlist.id);
    data.index++;
    store.set(tagString, data, STORE_TAGS_EXPIRY);
    this.played.push(playlist.id);
    store.set(STORE_PLAYED, this.played);
  }

  fetchPlaylists({ tags = this.state.currentTags } = {}) {
    const cleanTags = tags.concat().sort().map(tag => tag.toLowerCase());
    const tagString = cleanTags.toString();
    const data = store.get(tagString) || { page: 0, index: 0, playlists: [] };
<commit_msg>recursion is dangerous<commit_after>import Inferno from 'inferno';
import Component from 'inferno-component';
import { knuthShuffle } from 'knuth-shuffle';
import store from 'store';
import expirePlugin from 'store/plugins/expire';
import Dashboard from './Dashboard.jsx';
import Player from './Player.jsx';
import api from './utilities/api.js';
import help from './utilities/helpers.js';
import '../scss/App.scss';

const STORE_POPULAR = 'popular';
const STORE_PLAYED = 'played';
const STORE_POPULAR_EXPIRY = help.daysFromNow(7);
const STORE_TAGS_EXPIRY = help.daysFromNow(7);
const STORE_PLAYED_LIMIT = 500; // TODO
const PLAYLISTS_LIMIT = 10;

export default class App extends Component {
  constructor() {
    super();

    store.addPlugin(expirePlugin);

    this.state = {
      currentTags: [],
      playlist: false,
      playlistLoading: false,
      track: false,
      topTags: store.get(STORE_POPULAR) || [],
      relatedTags: [],
    };

    this.played = store.get(STORE_PLAYED) || [];

    this.addTag = this.addTag.bind(this);
    this.removeTag = this.removeTag.bind(this);
    this.fetchPlaylists = this.fetchPlaylists.bind(this);
    this.fetchNextSong = this.fetchNextSong.bind(this);

    if (!this.state.topTags.length) this.fetchTopTags();
  }

  fetchTopTags() {
    api.explore({ page: 1, per_page: 30 }).then(res => {
      const tags = [...this.state.topTags, ...res.filters];
      this.setState({ topTags: tags });
      store.set(STORE_POPULAR, tags, STORE_POPULAR_EXPIRY);
    });
  }

  addTag(tag) {
    const oldTag = this.state.currentTags[0];
    const newTags = !oldTag || tag === oldTag ? [tag] : [tag, oldTag];
    this.setState({ currentTags: newTags });
    this.fetchPlaylists({ tags: newTags });
  }

  removeTag(tag) {
    const index = this.state.currentTags.indexOf(tag);
    this.state.currentTags.splice(index, 1);
    this.setState({ currentTags: this.state.currentTags });
    return this.state.currentTags;
  }

  mapPlaylists(playlists) {
    return knuthShuffle(playlists).map(playlist => {
      return {
        id: playlist.id,
        colors: playlist.color_palette,
        cover: playlist.cover_urls.sq500,
      };
    });
  }

  mapRelatedTags(tags) {
    return tags.map(tag => {
      return {
        name: tag.name,
        image: tag.artist_avatar,
      }
    });
  }

  validPlaylist(playlist) {
    if (playlist) {
      const alreadyPlayed = this.played.indexOf(playlist.id) >= 0;
      if (alreadyPlayed) this.fetchPlaylists();
      else return true;
    } else {
      const removableTags = this.state.currentTags.length > 1;
      if (removableTags) this.fetchPlaylists({ tags: this.removeTag(1) });
    }

    return false;
  }

  loadPlaylist(tagString, data) {
    const playlist = data.playlists[data.index];
    data.index++;
    store.set(tagString, data, STORE_TAGS_EXPIRY);
    if (!this.validPlaylist(playlist)) return false;
    this.setState({ playlist: playlist, relatedTags: data.related });
    this.fetchNextSong(playlist.id);
    this.played.push(playlist.id);
    store.set(STORE_PLAYED, this.played);
  }

  fetchPlaylists({ tags = this.state.currentTags } = {}) {
    const cleanTags = tags.concat().sort().map(tag => tag.toLowerCase());
    const tagString = cleanTags.toString();
    const data = store.get(tagString) || { page: 0, index: 0, playlists: [] };

{'fraction_non_alphanumeric': 0.14339003282602208, 'fraction_numerical': 0.005968367651447329, 'mean_word_length': 3.305073859987155, '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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3048015', 'n_tokens_mistral': 2312, 'n_tokens_neox': 2222, 'n_words': 440}