您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Mark snatched torrents for tc
// ==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); } })();