tehConnection Snatch Script

Mark snatched torrents for tc

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name           tehConnection Snatch Script
// @namespace      http://tehconnection.eu
// @description    Mark snatched torrents for tc
// @author         jonls on what.cd  (adapted for TC by Dafreak)
// @include        http://tehconnection.eu/*
// @include        https://tehconnection.eu/*
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_deleteValue
// @grant           GM_xmlhttpRequest
// @grant           GM_registerMenuCommand
// @grant           GM_addStyle
// @grant           GM_log
// @version        0.2
// @date           2010-10-27
// ==/UserScript==

(function() {
	var DEFAULT_STYLE =
		'.group_snatched { color: #E5B244; } '+
		'.snatched { color: #35BF00; } '+
		'.uploaded { color: red; } '+
		'.leeching { color: #2B75A1; }'+
		'.seeding { border-bottom: 1px dotted red; }';
	
	var AUTO_UPDATE_INTERVAL = 10*60; /* seconds */

	/* Throttled proxy */
	function Proxy(url_base, delay) {
		var last_req = new Date(0);
		var queue = [];
		var processing = false;

		return {
			get: function(req) {
				var now = new Date();
				queue.push(req);
				if (!processing) {
					/* Race condition: atomic test and set would be appropriate here, to ensure thread safety (is it a problem?) */
					processing = true;
					var diff = last_req.getTime() + delay - now.getTime();
					if (diff > 0) {
						var that = this;
						window.setTimeout(function() { that.process_queue(); }, diff);
					} else {
						this.process_queue();
					}
				}
			},

			process_queue: function() {
				var req = queue.shift();
				this.do_request(req);
				processing = (queue.length > 0);
				if (processing) {
					var that = this;
					window.setTimeout(function() { that.process_queue(); }, delay);
				}
			},

			do_request: function(req) {
				last_req = new Date();
				var timer;
				var req_timed_out = false; /* We cannot abort a request, so we need keep track of whether it timed out */

				/* Create timeout handler */
				timer = window.setTimeout(function() {
					/* Race condition: what if the request returns successfully now? */
					req_timed_out = true;
					if (req.error) req.error(null, 'Network timeout');
				}, req.timeout || 10000);

				/* Do the actual request */
				GM_xmlhttpRequest({
					method: req.method || 'GET',
					url: url_base+req.url,
					headers: { 'User-Agent': navigator.userAgent, 'Accept': req.accept || 'text/xml' },
					onload: function(response) {
						window.clearTimeout(timer);
						if (!req_timed_out) req.callback(response);
					},
					onerror: function(response) {
						window.clearTimeout(timer);
						if (!req_timed_out && req.error) req.error(response, 'GM_xmlhttpRequest error');
					}
				});
			}
		};
	}

	
	/* Simple rounding (extracted from jQuery Corner)*/
	$.fn.round = function(radius) {
		radius = radius || "10px";
		return this.each(function(i) {
			if ($.browser.mozilla && /gecko/i.test(navigator.userAgent)) {
				$(this).css('-moz-border-radius', radius);
			} else if ($.browser.safari && $.browser.version >= 3) {
				$(this).css('-webkit-border-radius', radius);
			}
		});
	};
	
	/* Global status area - feel free to reuse in your own scripts :)
	   Requires jQuery and the round extension above. */
	function StatusBox(title) {
		/* Setup status area */
		var status_area = $('#greasemonkey_status_area').eq(0);
		if (status_area.length == 0) {
			status_area = $('<div id="greasemonkey_status_area"></div>').css({
				'position': 'fixed',
				'top': '0', 'right': '0',
				'margin': '20px',
				'width': '20%',
				'z-index': 500
			});
			$('body').append(status_area);
		}

		/* Create box */
		var box = $('<div></div>').hide();
		box.css({
			'color': 'white',
			'background-color': 'black',
			'opacity': 0.5,
			'margin': '0 0 10px 0',
			'padding': '10px 10px 20px 10px'}).round();
		box.append($('<div>'+title+'</div>').css('font-weight', 'bold'));

		/* Create contents area */
		var contents = $('<div></div>');
		box.append(contents);

		var timer = null;
		var timeout = 0;
		var inhibit_fade = false;

		function set_visible(visible) {
			if (visible && box.is(':hidden')) box.fadeIn(500);				
			else if (!visible && box.is(':visible')) box.fadeOut(500);
		}

		function clear_timer() {
			if (timer) {
				window.clearTimeout(timer);
				timer = null;
			}
		}

		function set_timer() {
			if (!timer && timeout > 0) {
				timer = window.setTimeout(function() { clear_timer(); set_visible(false); }, timeout);
			}			
		}

		function update_timer(t) {
			clear_timer();
			timeout = t;
			if (!inhibit_fade) set_timer();
		}

		function set_inhibit_fade(inhibit) {
			inhibit_fade = inhibit;
			if (!inhibit_fade) { set_timer(); }
			else clear_timer();
		}

		/* Register event handlers */
		box.mouseenter(function(event) {
			set_inhibit_fade(true);
			$(this).fadeTo(500, 0.8);
		});

		box.mouseleave(function(event) {
			set_inhibit_fade(false);
			$(this).fadeTo(500, 0.5);
		});

		box.click(function(event) {
			clear_timer();
			set_visible(false);
		});

		/* Append to global status area */
		status_area.append(box);

		return {
			contents: function() {
				return contents;
			},

			show: function(t) {
				t = t || 0;
				update_timer(t);
				set_visible(true);
			},

			hide: function() {
				clear_timer();
				set_visible(false);
			}
		};
	}

	/* Cache */
	function Cache(name, def_value) {
		var cache;
		return {
			serialize: function() {
				GM_setValue(name, uneval(cache));
			},
			unserialize: function() {
				cache = eval(GM_getValue(name, 'false'));
				if (!cache) cache = $.extend({}, def_value); /* clone */
				return cache;
			},
			clear: function() {
				cache = $.extend({}, def_value); /* clone */
				this.serialize();
			}
		};
	}

	
	/* Get what.CD base URL */
	var whatcd_url_base = document.URL.match(/^(https:\/\/tehconnection\.eu|http:\/\/tehconnection\.eu)/)[1];

	/* Create proxy */
	var whatcd_proxy = Proxy(whatcd_url_base, 1000);

	/* Get user id of this user */
	var whatcd_id = (function() {
		var m = $('#header .username').eq(0).attr('href').match(/user\.php\?id=(\d+)/);
		if (m) return m[1];
		return null;
	})();

	if (!whatcd_id) return; /* Exceptional condition: User ID not found */

	/* Create status box */
	var status = StatusBox('TehConnection.Eu Snatched');

	/* Cache of snatched torrents */
	var snatch_cache = Cache('snatch_cache', { groups: {}, torrents: {} });

	/* Scan torrent table in doc and mark links as type in cache */
	function scan_torrent_page(doc, type) {
		var torrent_table = doc.find('.torrent_table').eq(0);
		if (torrent_table.length == 0){ 	
			return 0;
		}

		var found = 0;

		var d = snatch_cache.unserialize();
		torrent_table.find('tr').not('.colhead').each(function(i) {
			/* Find group and torrent ID */
			var group_id;
			var torrent_id;
			var link = $(this).children('td').eq(1).children('a:last').eq(0);
			var m = link.attr('href').match(/torrents\.php\?id=(\d+)&torrentid=(\d+)/);
			if (m) {
				group_id = m[1];
				torrent_id = m[2];
			} else {
				m = link.attr('href').match(/torrents\.php\?id=(\d+)/);
				if (m) {
					group_id = m[1];
					link = $(this).children('td').eq(1).children('span').eq(0).children('a').eq(0);
					m = link.attr('href').match(/torrents\.php\?action=download&id=(\d+)/);
					if (m) torrent_id = m[1];
				}

				if (!m) {
					status.contents().append('<div><span style="color: red;">Failed:</span> '+$(this).children('td').eq(1).text()+'</div>');
					status.show();
				}
			}

			/* Save in cache */
			if (group_id && torrent_id) {
				if (!d.torrents[torrent_id] ||
						(type != 'seeding' && d.torrents[torrent_id].type != type) ||
						(type == 'seeding' && !d.torrents[torrent_id].seeding)) {
					var name = $.trim($(this).children('td').eq(1).clone().children('span, div').remove().end().text().match(/\s+([^[]+)(\s+\[|$)/)[1]);
					d.groups[group_id] = { name: name };
					if (type == 'seeding') { /* Special case seeding */
						if (d.torrents[torrent_id]) d.torrents[torrent_id].seeding = true;
						else d.torrents[torrent_id] = { type: 'unknown', seeding: true };
					} else {
						if (d.torrents[torrent_id]) d.torrents[torrent_id].type = type;
						else d.torrents[torrent_id] = { type: type, seeding: false };
					}
					found += 1;
				}
			}
		});

		if (found == 0) return 0;

		snatch_cache.serialize();
		return found;
	}

	/* Fetch and scan all pages of type, call callback when done */
	function scan_all_torrent_pages(type, page_cb, finish_cb) {
		var page = 1;
		var total = 0;

		function request_url() {
			return '/torrents.php?type='+type+'&userid='+whatcd_id+'&page='+page;
		}

		function error_handler(response, reason) {
			alert("Error in loading snatches");
			status.contents().append('<div><span style="color: red;">Error:</span> Unable to fetch '+type+' page '+page+' ('+reason+')</div>');
			status.show();
			finish_cb(total);
		}

		function page_handler(response) {
			if (response.status == 200) {
				
				var doc = $(new DOMParser().parseFromString(response.responseText, 'text/xml'));
				
				page_cb(type, page);
				
				var found = scan_torrent_page(doc, type);

				total += found;
				if (found == 0) { finish_cb(type, total); return; } /* End of asynchronous chain */

				page += 1;
				whatcd_proxy.get({ url: request_url(), callback: page_handler, error: error_handler });
			} else {
				error_handler(response, 'HTTP '+response.status);
			}
		}

		whatcd_proxy.get({ url: request_url(), callback: page_handler, error: error_handler });
	}

	/* Reset command */
	GM_registerMenuCommand('TehConnection.Eu Snatched: Reset', function() { snatch_cache.clear(); GM_setValue('last_update', '0'); location.reload(); });

	/* Register menu command to enter custom style */
	var custom_style = GM_getValue('custom_style', DEFAULT_STYLE);
	GM_registerMenuCommand('TehConnection.Eu Snatched: Enter custom style...', function() {
		var style = window.prompt('Enter CSS style (or blank to use default)\nClasses: .group_snatched, .snatched, .uploaded, .leeching, .seeding', custom_style);
		if (style) {
			GM_setValue('custom_style', style);
			location.reload();
		} else if (style == '') {
			GM_deleteValue('custom_style');
			location.reload();
		}
	});

	/* Inject CSS style */
	GM_addStyle(custom_style);

	/* Mark all links to torrents that are snatched/uploaded/leeching */
	function mark_snatched_links() {
		var d = snatch_cache.unserialize();

		/* Go through all links */
		$('#content').find('a').each(function(i) {
			var href = $(this).attr('href');
			if (href) {
				var group_id;
				var torrent_id;

				/* Find and mark links to snatched torrents */
				var m = href.match(/torrents\.php\?id=(\d+)&torrentid=(\d+)/);
				if (m) {
					group_id = m[1];
					torrent_id = m[2];
				} else {
					m = href.match(/torrents\.php\?torrentid=(\d+)/);
					if (m) {
						torrent_id = m[1];
					} else {
						m = href.match(/torrents\.php\?id=(\d+)/);
						if (m) group_id = m[1];
					}
				}

				/* Add classes */
				if (group_id && d.groups[group_id] &&
						(!torrent_id || !$(this).parent().parent().is('.group_torrent'))) {
					$(this).addClass('group_snatched');
				}
				if (torrent_id && d.torrents[torrent_id]) {
					$(this).addClass(d.torrents[torrent_id].type);
					if (d.torrents[torrent_id].seeding) $(this).addClass('seeding');
				}

				/* Change text if text is url */
				if ($(this).text() == $(this).attr('href') && group_id &&
						d.groups[group_id] && d.groups[group_id].name) {
					$(this).text(d.groups[group_id].name);
				}
			}
		});

		/* Mark links on album page in torrent table */
		if (/tehconnection\.eu\/torrents\.php/.test(document.URL)) {
			/* Parse search */
			var search = {};
			var search_list = document.location.search.substring(1).split('&');
			for (var i = 0; i < search_list.length; i++) {
				var pair = search_list[i].split('=');
				search[pair[0]] = pair[1];
			}

			if (search.id) {
				/* Album page */
				$('#content .torrent_table:first tr.group_torrent').each(function(i) {
					/* Find torrent id */
					var torrent_id;
					$(this).children('td').eq(0).children('span').eq(0).children('a').each(function(i) {
						var href = $(this).attr('href');
						if (href) {
							var m = href.match(/torrents\.php\?torrentid=(\d+)/);
							if (m) {
								torrent_id = m[1];
								$(this).removeClass('group_snatched snatched uploaded leeching seeding');
								return false;
							}
						}
					});

					if (torrent_id && d.torrents[torrent_id]) {
						var link = $(this).children('td').eq(0).children('a').eq(0);
						link.addClass(d.torrents[torrent_id].type);
						if (d.torrents[torrent_id].seeding) link.addClass('seeding');
					}
				});
			}
		}
	}

	/* Mark torrent as leeching when download link is clicked */
	function mark_download_links() {
		$('#content').find('a').each(function(i) {
			var href = $(this).attr('href');
			if (href) {
				/* Find download links */
				var m = href.match(/torrents\.php\?action=download&id=(\d+)/);
				if (m) {
					var torrent_id = m[1];
					$(this).click(function(event) {
						var d = snatch_cache.unserialize();
						d.torrents[torrent_id] = { type: 'leeching', seeding: false };
						snatch_cache.serialize();
						mark_snatched_links();
					});
				}
			}
		});
	}
	

	/* Scan current page */
	if (/tehconnection\.eu\/torrents\.php/.test(document.URL)) {
		/* Parse search */
		var search = {};
		var search_list = document.location.search.substring(1).split('&');
		for (var i = 0; i < search_list.length; i++) {
			var pair = search_list[i].split('=');
			search[pair[0]] = pair[1];
		}

		if ((search.type == 'snatched' || search.type == 'uploaded'
				|| search.type == 'seeding' || search.type == 'leeching') && search.userid == whatcd_id) {
			var scan_status = $('<div>Scanning current page... <span></span></div>');
			status.contents().append(scan_status);
			status.show();

			/* Scan current page */
			var found = scan_torrent_page($(document), search.type);

			scan_status.children('span').text('Done ('+((found > 0) ? (found+' updates found') : 'no updates found')+')')
			status.show(5000);
		}
	}

	/* Mark links */
	mark_download_links();
	mark_snatched_links();

	/* Auto update */
	var now = new Date();
	var last_update = parseInt(GM_getValue('last_update', '0'));
	if (last_update + AUTO_UPDATE_INTERVAL*1000 < now.getTime()) {
		GM_setValue('last_update', now.getTime().toString());
		var jobs = 4;
		var total_found = {};

		/* Show auto update status */
		if (last_update == 0) {
			var update_status = {
				snatched: $('<div>Updating snatched: <span>Initializing...</span></div>'),
				uploaded: $('<div>Updating uploaded: <span>Initializing...</span></div>'),
				leeching: $('<div>Updating leeching: <span>Initializing...</span></div>'),
				seeding: $('<div>Updating seeding: <span>Initializing...</span></div>')
			};

			for (var type in update_status) status.contents().append(update_status[type]);
			status.show();
		}

		function scan_page_handler(type, page) {
			if (last_update == 0) {
				update_status[type].children('span').text('Page '+page+'...');
				status.show();
			}
		}

		function scan_finished_handler(type, found) {
			if (last_update == 0) {
				update_status[type].children('span').text('Done ('+((found > 0) ? (found+' updates found') : 'no updates found')+')');
			}

			jobs -= 1;
			total_found[type] = found;

			if (jobs == 0) {
				mark_snatched_links();
				if (last_update == 0) {
					var total = [];
					for (var type in total_found) if (total_found[type] > 0) total.push(type+': '+total_found[type]);
					status.contents().append('<div>Auto update done</div>');
					status.show(5000);
				}
			}
		}

		/* Rescan all types of torrent lists */
		scan_all_torrent_pages('snatched', scan_page_handler, scan_finished_handler);
		scan_all_torrent_pages('uploaded', scan_page_handler, scan_finished_handler);
		scan_all_torrent_pages('leeching', scan_page_handler, scan_finished_handler);
		scan_all_torrent_pages('seeding', scan_page_handler, scan_finished_handler);
	}
})();