<commit_before>'use strict';

/**
 * Background script entry point
 *
 * - sets up injecting mechanism for supported sites
 * - creates controllers for each recognized tab
 * - sets up all chrome.* listeners, which are forwarded controllers if needed
 * - checks auth status on run (browser start or extension enabling) and prompts for login if needed
 */
require([
	'services/background-ga',
	'services/lastfm',
	'notifications',
	'inject',
	'objects/injectResult',
	'pageAction',
	'controller',
	'chromeStorage'
], function(GA, LastFM, Notifications, inject, injectResult, PageAction, Controller, ChromeStorage) {

	/**
	 * Single controller instance for each tab with injected script
	 * This allows us to work with tabs independently
	 */
	var tabControllers = {};

	/**
	 * Flag for "page session" where at least single injection occurred
	 * Used for tracking number of actually active users
	 * @type {boolean}
	 */
	var isActiveSession = false;

	/**
	 * Callback for injecting script.
	 *
	 * @param {InjectResult} result InjectResult object
	 */
	var injectCb = function(result) {
		var tabId = result.getTabId();

		// no match - do cleanup
		if (result.getResult() === injectResult.results.NO_MATCH) {
			// remove controller if any
			if (tabControllers[tabId] !== undefined) {
				delete tabControllers[tabId];
			}

			// hide action icon - there may be any
			try {
				chrome.pageAction.hide(tabId);
			} catch (e) {
				// ignore, the tab may no longer exist
			}
			return;
		}

		// matched, but the connector is disabled
		if (result.getResult() === injectResult.results.MATCHED_BUT_DISABLED) {
			new PageAction(tabId).setWebsiteDisabled();
			return;
		}

		// matched, create controller if needed
		if (result.getResult() === injectResult.results.MATCHED_AND_INJECTED) {
			// intentionally overwrite previous controller, if any
			tabControllers[tabId] = new Controller(tabId, result.getConnector());

			GA.event('core', 'inject', result.getConnector().label);

			if (!isActiveSession) {
				isActiveSession = true;
				GA.send('pageview', '/background-injected?version=' + chrome.app.getDetails().version);
			}
		}
	};

	/**
	 * Return controller for given tab. There should always be one.
	 * @param  {Number} tabId Tab ID
	 * @return {Object} Controller instance for tab
	 */
	function getControllerByTabId(tabId) {
		if (!tabControllers[tabId]) {
			console.warn('Missing controller for tab ' + tabId);
		}

		return tabControllers[tabId];
	}

	// setup listener for messages from connectors
	chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
		var ctrl;

		switch (request.type) {
			case 'v2.stateChanged':
				ctrl = getControllerByTabId(sender.tab.id);
				if (ctrl) {
					ctrl.onStateChanged(request.state);
				}
				break;

			// Returns current song object - used in page action popup.
			// Tab ID is stored inside request data
			case 'v2.getSong':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					sendResponse(ctrl.getCurrentSong()); // object or null
				}
				break;

			// Returns current song object - used in page action popup.
			// Tab ID is stored inside request data
			case 'v2.correctSong':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.setUserSongData(request.data);
				}
				break;

			case 'v2.toggleLove':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.toggleLove(request.data, sendResponse);
				}
				break;

			case 'v2.resetSongData':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.resetSongData();
				}
				break;
		}

		return true;
	});

	// setup listener for tab updates
	chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
		// wait for navigation to complete (this does not mean page onLoad)
		if (changeInfo.status !== 'complete') {
			return;
		}

		inject.onTabsUpdated(tabId, changeInfo, tab, injectCb);
	});
	chrome.tabs.onRemoved.addListener((tabId) => {
		if (tabControllers[tabId]) {
			console.log(`Tab ${tabId}: remove controller`);
			delete tabControllers[tabId];
		}
	});

	// setup listener for page action clicks
	chrome.pageAction.onClicked.addListener(function(tab) {
		var ctrl = getControllerByTabId(tab.id);
		if (ctrl) {
			ctrl.onPageActionClicked(tab);
		}
	});


	/**
	 * Called on the extension start, after maintenance storage reads/writes are done
	 */
	function startup() {
		// track background page loaded - happens once per browser session
		GA.send('pageview', '/background-loaded?version=' + chrome.app.getDetails().version);

		// debug log internal storage state for people who send logs (tokens are anonymized)
		ChromeStorage.debugLog('Core');

		// check session ID status and show notification if authentication is needed
		LastFM.getSession(function(sessionID) {
			if (!sessionID) {
				Notifications.showAuthenticate(LastFM.getAuthUrl);
			}
		});
	}

	startup();
});<commit_msg>Update extension version in storage<commit_after>'use strict';

/**
 * Background script entry point
 *
 * - sets up injecting mechanism for supported sites
 * - creates controllers for each recognized tab
 * - sets up all chrome.* listeners, which are forwarded controllers if needed
 * - checks auth status on run (browser start or extension enabling) and prompts for login if needed
 */
require([
	'services/background-ga',
	'services/lastfm',
	'notifications',
	'inject',
	'objects/injectResult',
	'pageAction',
	'controller',
	'chromeStorage'
], function(GA, LastFM, Notifications, inject, injectResult, PageAction, Controller, ChromeStorage) {

	/**
	 * Single controller instance for each tab with injected script
	 * This allows us to work with tabs independently
	 */
	var tabControllers = {};

	/**
	 * Flag for "page session" where at least single injection occurred
	 * Used for tracking number of actually active users
	 * @type {boolean}
	 */
	var isActiveSession = false;

	/**
	 * Callback for injecting script.
	 *
	 * @param {InjectResult} result InjectResult object
	 */
	var injectCb = function(result) {
		var tabId = result.getTabId();

		// no match - do cleanup
		if (result.getResult() === injectResult.results.NO_MATCH) {
			// remove controller if any
			if (tabControllers[tabId] !== undefined) {
				delete tabControllers[tabId];
			}

			// hide action icon - there may be any
			try {
				chrome.pageAction.hide(tabId);
			} catch (e) {
				// ignore, the tab may no longer exist
			}
			return;
		}

		// matched, but the connector is disabled
		if (result.getResult() === injectResult.results.MATCHED_BUT_DISABLED) {
			new PageAction(tabId).setWebsiteDisabled();
			return;
		}

		// matched, create controller if needed
		if (result.getResult() === injectResult.results.MATCHED_AND_INJECTED) {
			// intentionally overwrite previous controller, if any
			tabControllers[tabId] = new Controller(tabId, result.getConnector());

			GA.event('core', 'inject', result.getConnector().label);

			if (!isActiveSession) {
				isActiveSession = true;
				GA.send('pageview', '/background-injected?version=' + chrome.app.getDetails().version);
			}
		}
	};

	/**
	 * Return controller for given tab. There should always be one.
	 * @param  {Number} tabId Tab ID
	 * @return {Object} Controller instance for tab
	 */
	function getControllerByTabId(tabId) {
		if (!tabControllers[tabId]) {
			console.warn('Missing controller for tab ' + tabId);
		}

		return tabControllers[tabId];
	}

	// setup listener for messages from connectors
	chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
		var ctrl;

		switch (request.type) {
			case 'v2.stateChanged':
				ctrl = getControllerByTabId(sender.tab.id);
				if (ctrl) {
					ctrl.onStateChanged(request.state);
				}
				break;

			// Returns current song object - used in page action popup.
			// Tab ID is stored inside request data
			case 'v2.getSong':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					sendResponse(ctrl.getCurrentSong()); // object or null
				}
				break;

			// Returns current song object - used in page action popup.
			// Tab ID is stored inside request data
			case 'v2.correctSong':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.setUserSongData(request.data);
				}
				break;

			case 'v2.toggleLove':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.toggleLove(request.data, sendResponse);
				}
				break;

			case 'v2.resetSongData':
				ctrl = getControllerByTabId(request.tabId);
				if (ctrl) {
					ctrl.resetSongData();
				}
				break;
		}

		return true;
	});

	// setup listener for tab updates
	chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
		// wait for navigation to complete (this does not mean page onLoad)
		if (changeInfo.status !== 'complete') {
			return;
		}

		inject.onTabsUpdated(tabId, changeInfo, tab, injectCb);
	});
	chrome.tabs.onRemoved.addListener((tabId) => {
		if (tabControllers[tabId]) {
			console.log(`Tab ${tabId}: remove controller`);
			delete tabControllers[tabId];
		}
	});

	// setup listener for page action clicks
	chrome.pageAction.onClicked.addListener(function(tab) {
		var ctrl = getControllerByTabId(tab.id);
		if (ctrl) {
			ctrl.onPageActionClicked(tab);
		}
	});

	/**
	 * Replace the extension version stored in
	 * local storage by current one.
	 */
	function updateVersionInStorage() {
		let storage = ChromeStorage.getNamespace('Core');
		storage.get((data) => {
			data.appVersion = chrome.app.getDetails().version;
			storage.set(data, startup);
		});

		// debug log internal storage state for people who send logs (tokens are anonymized)
		ChromeStorage.debugLog('Core');
	}

	/**
	 * Called on the extension start, after maintenance storage reads/writes are done
	 */
	function startup() {
		updateVersionInStorage();

		// track background page loaded - happens once per browser session
		GA.send('pageview', '/background-loaded?version=' + chrome.app.getDetails().version);

		// check session ID status and show notification if authentication is needed
		LastFM.getSession(function(sessionID) {
			if (!sessionID) {
				Notifications.showAuthenticate(LastFM.getAuthUrl);
			}
		});
	}

	startup();
});
{'fraction_non_alphanumeric': 0.11854964816262706, 'fraction_numerical': 0.000977326035965598, 'mean_word_length': 3.548, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, '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': '4975223', 'n_tokens_mistral': 3539, 'n_tokens_neox': 3024, 'n_words': 872}