MyAnimeList - Extended Favourites

Adds the ability to have more favourites than the current limit allows.

// ==UserScript==
// @name         MyAnimeList - Extended Favourites
// @namespace    https://github.com/DakuTree/userscripts
// @author       Daku (admin@codeanimu.net)
// @description  Adds the ability to have more favourites than the current limit allows.
// @homepageURL  https://github.com/DakuTree/userscripts
// @supportURL   https://github.com/DakuTree/userscripts/issues
// @include      /^http[s]?:\/\/myanimelist\.net\/(anime|manga|people|character|profile)(\/|\.php\?id\=).*$/
// @updated      2016-08-24
// @version      2.2.6
// @grant        GM_addStyle
// @require      http://ajax.googleapis.com/ajax/libs/jquery/2.2.1/jquery.min.js
// ==/UserScript==

var backend = "https://codeanimu.net/userscripts/myanimelist.net/backend/";
var dev = false; //Enable if you want some dev stuff

$(document).ready(function () {
	if (dev == true) {
		if (jQuery.fn.jquery !== '2.2.1') {
			alert('jQuery mismatch!\nRunning ' + jQuery.fn.jquery + '.\nExpected 2.2.1.');
		}
		window.onerror = function (msg, url, linenumber) {
			alert('Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
			error = true;
			return true;
		}
	}

	var userid = (document.cookie.match('(^|; )(A|Y)=([^;]*)') || 0)[3] || find_userid() || 0,
		type;

	if (/myanimelist\.net\/(profile)\/.*$/.test(self.location.href)) {
		GM_addStyle("\
			.user-favorites-outer { max-height: 9999px !important; }\
			.js-btn-truncate { display: none !important; }\
		");

		var profileID = $('[name=profileMemId]').val(); //Profile ID is different than userid
		$.getJSON(backend + "mf_index.php", { userid: profileID }, function (data) {
			// var anime      = $('.user-favorites h5:contains("Anime") ~ ul'),
			// manga      = $('.user-favorites h5:contains("Manga") ~ ul'),
			// characters = $('.user-favorites h5:contains("Characters") ~ ul'),
			// people     = $('.user-favorites h5:contains("People") ~ ul');

			$.each(data, function () {
				var type = $(this)[0]['type'];
				type = (type == 0 ? "anime" : (type == 1 ? "manga" : (type == 2 ? "character" : (type == 6 ? "people" : null))));
				var type_id = $(this)[0]['type_id'],
					name = $(this)[0]['name'],
					manga_type = (name.indexOf("(Manga)") > -1 ? "Manga" : "Novel"),
					url = 'https://myanimelist.net/' + type + '/' + type_id,
					preview_url = $(this)[0]['preview_url'].replace(/v\.jpg$/, '.jpg').replace(/t\.jpg$/, '.jpg'),
					series_title = $(this)[0]['series_title'],
					series_url = $(this)[0]['series_url'];
				name = name.replace(' (Manga)', '').replace(' (Novel)', '');

				$('<li/>', { class: 'list di-t mb8', style: 'background-color: #D5E4FF' }).append(
					$('<a/>', { class: 'di-tc image', href: url, style: 'background-image:url(\'' + preview_url + '\')' })).append(
						$('<div/>', { class: 'di-tc va-t pl8 data' }).append(
							$('<a/>', { href: url, text: name })).append(
								(type == "character" ?
									$('<br/>').add($('<span/>', { class: 'di-ib mt4 fn-grey2' }).append(
										$('<a/>', { href: series_url, class: 'fn-grey2', text: series_title })
									))
									: (type == "manga" ?
										$('<br/>').add(
											$('<span/>', { class: 'di-ib mt4 fn-grey2', text: manga_type }))
										: ""))
							)
					).appendTo($('.user-favorites h5:contains("' + type.substr(0, 1).toUpperCase() + type.substr(1) + '") ~ ul'));
			});
		});
	}
	else if (/myanimelist\.net\/(anime|manga|character|people)\/[0-9]+/.test(self.location.href) || /myanimelist\.net\/(anime|manga|character|people)\.php\?id\=.*/.test(self.location.href)) {
		if (userid == 0) return false;

		var tcheck = $('#horiznav_nav a:contains("Details")').attr('href').replace(/^.*myanimelist.net\//, '').replace(/^\//, '').split('/'),
			type = (tcheck[0] == "anime" ? 0 : (tcheck[0] == "manga" ? 1 : (tcheck[0] == "character" ? 2 : (tcheck[0] == "people" ? 6 : 0)))),
			id = tcheck[1];

		$('#profileRows a:contains("Favorites")').after(
			$('<a/>', { href: 'javascript:void(0);', style: 'font-weight: normal;' }).append(
				$('<span/>', { id: 'favOutputExtended', text: 'Add/Remove ExFavorites' })
			)
		);

		$('#favOutputExtended').click(function () {
			var name = $('#contentWrapper > div h1.h1').text().trim(),
				thumbURL = $('tbody tr:eq(0) div:eq(0) img').attr('src');

			var params = {
				userid: userid,
				type: type,
				type_id: id,
				name: name,
				preview_url: thumbURL.replace(/http[s]:\/\//, '')
			};

			if (type == 2) {
				var series = $('#content > table > tbody > tr > td:eq(0) .normal_header ~ table tr td:eq(1) a:eq(0)').first();
				params = $.extend(params, { series_title: series.text(), series_url: series.attr('href').replace(/http[s]:\/\//, '') });
			}
			$.get(backend + "mf_update.php", params, function (data) {
				$('#favOutputExtended').html(data);
			});
		});
	}

	function find_userid() {
		var userid,
			unsafeWindow = this['unsafeWindow'] || window;

		//#1: Check localStorage to see if userid is already set?
		//    Also if expired, delete localStorage.
		if (unsafeWindow.localStorage.getItem('userid')) {
			var userid_data = JSON.parse(unsafeWindow.localStorage.getItem('userid'));
			if (new Date().getTime() > userid_data['timestamp']) {
				unsafeWindow.localStorage.removeItem('userid');
				console.log('localstorage found userid but has expired');
			} else {
				userid = userid_data['userid'];
				console.log('localstorage found userid');
			}
		}

		if (!userid) {
			//#2: localstorage does not exists, manually try and find userid

			//#2.1: Check if user is online, and if so, get username.
			var userName;
			$.get('https://myanimelist.net/panel.php', function (data1) {
				userName = data1.match(/\/profile\/(.*?)"/)[1];
				console.log(userName);
				if (userName) {
					//2.2: Check profile for userID. It may be possible for the userID to still not exist.
					$.get('https://myanimelist.net/profile/' + userName, function (data2) {
						//since we're using an old version of jQuery, parsing the HTML is painful, so we're doing it the hacky way.
						userid = data2.match(/name="profileMemId"\s*[a-zA-Z="']*\s*value="([0-9]+)">/)[1];
						if (userid) {
							var expireTime = (14 * 24 * 60 * 60 * 1000); //2 weeks expire
							unsafeWindow.localStorage.setItem('userid', JSON.stringify({ 'userid': userid, 'timestamp': (new Date().getTime() + expireTime) }));
							console.log('userid found');
						}
					});
				} else {
					//User is not online, alert them?
				}
			});
		}

		return userid;
	}
});