<commit_before>'use strict';

/**
 * Module that contains some useful helper functions.
 */

const Util = {
	/**
	 * Extract artist and track from Youtube video title.
	 * @param  {String} videoTitle Youtube video title
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains artist and track fields
	 */
	processYoutubeVideoTitle(videoTitle) {
		if (!videoTitle) {
			return this.emptyArtistTrack;
		}

		// Remove [genre] from the beginning of the title
		let title = videoTitle.replace(/^\[[^\]]+\]\s*-*\s*/i, '');

		let { artist, track } = this.splitArtistTrack(title);
		if (artist === null && track === null) {
			// Look for Artist "Track"
			let artistTrack = title.match(/(.+?)\s"(.+?)"/);
			if (artistTrack) {
				artist = artistTrack[1];
				track = artistTrack[2];
			}
		}
		return { artist, track };
	},

	/**
	 * Parse given video URL and return video ID.
	 * @param  {String} videoUrl Video URL
	 * @return {String} Video ID
	 */
	getYoutubeVideoIdFromUrl(videoUrl) {
		let regExp = /v=([^#\&\?]*)/;
		let match = videoUrl.match(regExp);
		if (match) {
			return match[1];
		}

		return null;
	},

	/**
	 * Convert given time-string into seconds.
	 * @param  {String} str Time-string in h:m:s format
	 * @return {Number} Seconds
	 */
	stringToSeconds(str) {
		let s = str.toString().trim();
		let val, seconds = 0;

		for (let i = 0; i < 3; i++) {
			let idx = s.lastIndexOf(':');
			if (idx > -1) {
				val = parseInt(s.substr(idx + 1));
				seconds += val * Math.pow(60, i);
				s = s.substr(0, idx);
			} else {
				val = parseInt(s);
				seconds += val * Math.pow(60, i);
				break;
			}
		}

		return seconds || 0;
	},

	/**
	 * Find first occurence of possible separator in given string
	 * and return separator's position and size in chars or null.
	 * @param  {String} str String contains separator
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains position and width of separator
	 */
	findSeparator(str, separators = null) {
		if (str === null || str.length === 0) {
			return null;
		}

		if (!separators) {
			separators = this.separators;
		}

		for (let sep of separators) {
			let index = str.indexOf(sep);
			if (index > -1) {
				return { index, length: sep.length };
			}
		}

		return null;
	},

	/**
	 * Split string to artist and track.
	 * @param  {String} str String contains artist and track
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains artist and track fields
	 */
	splitArtistTrack(str, separators = null) {
		let artist = null;
		let track = null;

		if (str !== null) {
			let separator = this.findSeparator(str, separators);

			if (separator !== null) {
				artist = str.substr(0, separator.index);
				track = str.substr(separator.index + separator.length);
			}
		}

		return { artist, track };
	},

	/**
	 * Split string to current time and duration.
	 * @param  {String} str String contains current time and duration
	 * @param  {String} separator Separator
	 * @param  {Boolean} swap Swap currentTime and duration values
	 * @return {Object} Object contains 'currentTime' and 'duration' fields
	 */
	splitTimeInfo(str, sep = '/', swap = false) {
		let currentTime = null;
		let duration = null;

		if (str !== null) {
			let separator = this.findSeparator(str, [sep]);

			if (separator !== null) {
				currentTime = str.substr(0, separator.index);
				duration = str.substr(separator.index + separator.length);

				currentTime = this.stringToSeconds(currentTime);
				duration = this.stringToSeconds(duration);

				if (swap) {
					[currentTime, duration] = [duration, currentTime];
				}
			}
		}

		return { currentTime, duration };
	},

	/**
	 * Verify time value and return time as a Number object.
	 * @param  {Any} time Time value
	 * @return {Number} time value as a Number object
	 */
	escapeBadTimeValues(time) {
		if (typeof time !== 'number') {
			return null;
		}
		if (isNaN(time) || !isFinite(time)) {
			return null;
		}
		return Math.round(time);
	},

	/**
	 * Extract track art URL from CSS property.
	 * @param  {String} style CSS property
	 * @return {String} Track art URL
	 */
	extractUrlFromCssProperty(cssProperty) {
		let match = /url\((['"]?)(.*)\1\)/.exec(cssProperty);
		if (match) {
			return match[2].trim();
		}
		return null;
	},

	/**
	 * Inject script into document.
	 * @param {String} scriptUrl script URL
	 */
	injectScriptIntoDocument(scriptUrl) {
		let script = document.createElement('script');
		script.src = scriptUrl;
		script.onload = function () {
			this.parentNode.removeChild(this);
		};
		(document.head || document.documentElement).appendChild(script);
	},

	/**
	 * Default array of separators.
	 * Push new separators in the implementation if required.
	 *
	 * @type {Array}
	 */
	separators: [
		' -- ', '--', ' - ', ' – ', ' — ',
		' // ', '-', '–', '—', ':', '|', '///'
	],

	/**
	 * Object that contains no artist and track info.
	 * @type {Object}<commit_msg>Add function to split string by array of separators<commit_after>'use strict';

/**
 * Module that contains some useful helper functions.
 */

const Util = {
	/**
	 * Extract artist and track from Youtube video title.
	 * @param  {String} videoTitle Youtube video title
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains artist and track fields
	 */
	processYoutubeVideoTitle(videoTitle) {
		if (!videoTitle) {
			return this.emptyArtistTrack;
		}

		// Remove [genre] from the beginning of the title
		let title = videoTitle.replace(/^\[[^\]]+\]\s*-*\s*/i, '');

		let { artist, track } = this.splitArtistTrack(title);
		if (artist === null && track === null) {
			// Look for Artist "Track"
			let artistTrack = title.match(/(.+?)\s"(.+?)"/);
			if (artistTrack) {
				artist = artistTrack[1];
				track = artistTrack[2];
			}
		}
		return { artist, track };
	},

	/**
	 * Parse given video URL and return video ID.
	 * @param  {String} videoUrl Video URL
	 * @return {String} Video ID
	 */
	getYoutubeVideoIdFromUrl(videoUrl) {
		let regExp = /v=([^#\&\?]*)/;
		let match = videoUrl.match(regExp);
		if (match) {
			return match[1];
		}

		return null;
	},

	/**
	 * Convert given time-string into seconds.
	 * @param  {String} str Time-string in h:m:s format
	 * @return {Number} Seconds
	 */
	stringToSeconds(str) {
		let s = str.toString().trim();
		let val, seconds = 0;

		for (let i = 0; i < 3; i++) {
			let idx = s.lastIndexOf(':');
			if (idx > -1) {
				val = parseInt(s.substr(idx + 1));
				seconds += val * Math.pow(60, i);
				s = s.substr(0, idx);
			} else {
				val = parseInt(s);
				seconds += val * Math.pow(60, i);
				break;
			}
		}

		return seconds || 0;
	},

	/**
	 * Find first occurence of possible separator in given string
	 * and return separator's position and size in chars or null.
	 * @param  {String} str String contains separator
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains position and width of separator
	 */
	findSeparator(str, separators = null) {
		if (str === null || str.length === 0) {
			return null;
		}

		if (!separators) {
			separators = this.separators;
		}

		for (let sep of separators) {
			let index = str.indexOf(sep);
			if (index > -1) {
				return { index, length: sep.length };
			}
		}

		return null;
	},

	/**
	 * Split string to artist and track.
	 * @param  {String} str String contains artist and track
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains artist and track fields
	 */
	splitArtistTrack(str, separators = null) {
		let [artist, track] = this.splitString(str, separators);
		return { artist, track };
	},

	/**
	 * Split string to current time and duration.
	 * @param  {String} str String contains current time and duration
	 * @param  {String} separator Separator
	 * @param  {Boolean} swap Swap currentTime and duration values
	 * @return {Object} Array of strings
	 */
	splitTimeInfo(str, sep = '/', swap = false) {
		let currentTime = null;
		let duration = null;

		if (str !== null) {
			let separator = this.findSeparator(str, [sep]);

			if (separator !== null) {
				currentTime = str.substr(0, separator.index);
				duration = str.substr(separator.index + separator.length);

				currentTime = this.stringToSeconds(currentTime);
				duration = this.stringToSeconds(duration);

				if (swap) {
					[currentTime, duration] = [duration, currentTime];
				}
			}
		}

		return { currentTime, duration };
	},

	/**
	 * Split string to two ones using array of separators.
	 * @param  {String} str Any string
	 * @param  {Array} separators Array of separators
	 * @return {Object} Object contains first and second parts of string
	 */
	splitString(str, separators = null) {
		let first = null;
		let second = null;

		if (str !== null) {
			let separator = this.findSeparator(str, separators);

			if (separator !== null) {
				first = str.substr(0, separator.index);
				second = str.substr(separator.index + separator.length);
			}
		}

		return [first, second];
	},

	/**
	 * Verify time value and return time as a Number object.
	 * @param  {Any} time Time value
	 * @return {Number} time value as a Number object
	 */
	escapeBadTimeValues(time) {
		if (typeof time !== 'number') {
			return null;
		}
		if (isNaN(time) || !isFinite(time)) {
			return null;
		}
		return Math.round(time);
	},

	/**
	 * Extract track art URL from CSS property.
	 * @param  {String} style CSS property
	 * @return {String} Track art URL
	 */
	extractUrlFromCssProperty(cssProperty) {
		let match = /url\((['"]?)(.*)\1\)/.exec(cssProperty);
		if (match) {
			return match[2].trim();
		}
		return null;
	},

	/**
	 * Inject script into document.
	 * @param {String} scriptUrl script URL
	 */
	injectScriptIntoDocument(scriptUrl) {
		let script = document.createElement('script');
		script.src = scriptUrl;
		script.onload = function() {
			this.parentNode.removeChild(this);
		};
		(document.head || document.documentElement).appendChild(script);
	},

	/**
	 * Default array of separators.
	 * Push new separators in the implementation if required.
	 *
	 * @type {Array}
	 */
	separators: [
		' -- ', '--', ' - ', ' – ', ' — ',
		' // ', '-', '–', '—', ':', '|', '///'
	],

	/**
	 * Object that contains no artist and track info.
	 * @type {Object}
{'fraction_non_alphanumeric': 0.15045533811276884, 'fraction_numerical': 0.003875217981011432, 'mean_word_length': 3.035574667709148, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '2600389', 'n_tokens_mistral': 3802, 'n_tokens_neox': 3265, 'n_words': 1009}