Sick Beard view and track

Keep track of what episodes you've seen and link to file for easy viewing

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Sick Beard view and track
// @namespace   armeagle.nl
// @include     http://*:8081/home/displayShow?show=*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @version     1.1
// @grant       none
// @run-at      document-end
// @description Keep track of what episodes you've seen and link to file for easy viewing
// ==/UserScript==

(function() {
// Set replace depending on how the directory is mounted.
var path_replace = {'/volume1/Series/' : 'file:///I:/'};
var watched_color = '#aaaaff';

// add querystring getter
function getQueryStringParameter(name) {
    var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

var showId = getQueryStringParameter('show');

/** Change filename to link **/
// Build base path to which the filenames can be added.
var basePath = $('div#summary table tbody tr td:contains(Location:)').next()[0].textContent;
$.each(path_replace, function(k, v) {
	basePath = basePath.replace(k, v);
});

// Loop through all filename cells and turn them to a link.
$('table.sickbeardTable2 tbody tr td.col-filename').each(function() {
    var fileName = $(this).text().trim();
    if ( ! fileName || fileName.length <= 0 ) {
        return;
    }

    var filePath = basePath + '/' + fileName;
    $(this).empty().append(
        $('<a/>').attr('href', filePath)
		.addClass('filelink')
        .text(fileName)
		.on('keydown', function(event) {
			return handleKeyEvent(event);
		})
    );
});
// end

// add watch(ed) button and states
$('table.sickbeardTable2 tbody tr td[colspan=9]').each(function() {
	if ( ! $(this).closest('tr').hasClass('seasonheader') ) {
		$(this).attr('colspan', 10);
		return;
	}
	$(this).before($('<td/>').append($('<button/>').attr('title', 'Mark whole season as watched').append('m').on('click', function() {
		var tr = $(this).closest('tr').next().next();
		while ( tr.attr('class').length ) {
			tr.find('td button.button-watch:not(.watched)').each(function() {
				$(this).trigger('click');
			});
			tr = tr.next();
		}
	})));
});

// add extra column to header rows
$('table.sickbeardTable2 tbody tr th:nth-child(1)').each(function() {
    $(this).next().next().next().next().next().after(
        $('<th/>')
    )
});

$('table.sickbeardTable2 tbody tr td:nth-child(1)').each(function() {
    var button = createButton(showId, $(this).find('input').attr('id'));

    if ( button && button.hasClass('watched') ) {
        $(this).closest('tr').addClass('watched');
    }
    $(this).next().next().next().next().next().after($('<td/>').append(button));
});


function createButton(showId, episodeId) {
    if ( ! showId || ! episodeId ) {
        return null;
    }

    var db = JSON.parse(localStorage.getItem('watchedTracker'));
    if ( db && db[showId] && db[showId][episodeId] ) {
        return $('<button/>').append('y').addClass('btn btn-mini button-watch watched')
            .on('click', function() {
                toggleWatched($(this), showId, episodeId);
            });
    } else {
        return $('<button/>').append('n').addClass('btn btn-mini button-watch')
            .on('click', function() {
                toggleWatched($(this), showId, episodeId);
            });
    }
}

function toggleWatched(button, showId, episodeId) {
    var db = JSON.parse(localStorage.getItem('watchedTracker'));
    if ( ! db ) { db = {}; }
    if ( ! db[showId] ) { db[showId] = {}; }
	if ( ! button.hasClass('watched') ) {
		db[showId][episodeId] = true ;
	} else {
		delete db[showId][episodeId];
	}
    localStorage.setItem('watchedTracker', JSON.stringify(db));

    button.empty().append( button.hasClass('watched') ? 'n' : 'y' );
    button.closest('tr').toggleClass('watched');
    button.toggleClass('watched');
}

// Handle key up/down events (prev/next link) and 'm' button to toggle marked. Else do nothing.
function handleKeyEvent(event) {
	var element = $(event.target);
	switch (event.keyCode) {
		case 40: //down
			var tr = element.closest('tr').next();
			var filelinks = tr.find('a.filelink');
			while ( tr && ! filelinks.length ) {
				tr = tr.next();
				filelinks = tr.find('a.filelink');
			}
			if ( filelinks.length ) {
				filelinks[0].focus();
			}
		break;
		case 38: // up
			var tr = element.closest('tr').prev();
			var filelinks = tr.find('a.filelink');
			while ( tr && ! filelinks.length ) {
				tr = tr.prev();
				filelinks = tr.find('a.filelink');
			}
			if ( filelinks.length ) {
				filelinks[0].focus();
			}
		break;
		case 77: // m
			element.closest('td').prev().prev().find('button').trigger('click'); // toggle marked
		break;
		default:
			return true;
	}
	event.stopPropagation();
	return false;
}
// end

// Add column for extra search links
$('table.sickbeardTable2 tbody tr th:nth-child(1)').each(function() {
    $(this).next().next().next().next().next().next().next().next().next().after(
        $('<th/>')
    )
});

$('table.sickbeardTable2 tbody tr td:nth-child(1)').each(function() {
    $(this).next().next().next().next().next().next().next().next().next().after(
		$('<td/>')
	);
});

// Add extra search links
$('table.sickbeardTable2 tbody tr td:last-child a.epSearch').each(function() {
	var showdetails = $(this).attr('href').match( new RegExp('.+season=([0-9]+)&episode=([0-9]+)'));
	var season = showdetails[1];
	var episode = showdetails[2];
	if ( season.length == 1 ) season = '0' + season;
	if ( episode.length == 1 ) episode = '0' + episode;
	var episode = ($('#content > h1.title > a').text() + ' S' + season + 'E' + episode).replace('&', ' ');

	// Add nzbindex search
	var img = $('<img/>').attr('src', $(this).find('img').attr('src')).attr('style', 'transform: rotate(270deg); margin-right: 5px;').attr('title', 'Search on NzbIndex');
	m_episode = episode.replace(' ', '+').replace(/[\(\)\[\]']/g,'');
	
	url = 'http://nzbindex.nl/search/?q=' + m_episode + '&age=&max=25&minage=&sort=agedesc&minsize=150&maxsize=&dq=&poster=&nfo=&complete=1&hidespam=0&hidespam=1&more=1';
	$(this).closest('td').prev().append($('<a/>').attr('href', url).append(img));

	// Add torrent search
	var img = $('<img/>').attr('src', $(this).find('img').attr('src')).attr('style', 'transform: rotate(90deg); margin-right: 5px;').attr('title', 'Search torrent');
	
	// add 1080p (isohunt)
//	m_episode = episode + ' 1080p';
	// replace whitespace with plus and remove some tokens
	m_episode = m_episode.replace(/ /g, '+').replace(/[\(\)\[\]']/g,'');
	
	//url = 'http://isohunt.to/torrents/advancedSearch?yform_advanced_search=1&SearchForm[allWords]='
	//+ m_episode
	//+ '&SearchForm[category]=0&SearchForm[language]=0&SearchForm[seederCount]=1&submit=Search';
//	url = 'https://isohunt.to/torrents/?ihq=' + m_episode;
	// TPB sorted on size desc.
	url = 'https://thepiratebay.org/search/' + m_episode +'/0/5/0';
	
	$(this).closest('td').prev().append($('<a/>').attr('href', url).append(img));
	/*
	var $form = $('<form/>').attr('action', url).attr('target','blank').attr('method','GET');
	$form.attr('class', 'mysearch').append($('<input/>').attr('type', 'hidden').attr('name', 'SearchString1').attr('value', episode));
	$form.append($('<button/>').attr('style', 'background: url(' + $(this).find('img').attr('src') + ')' ));
	$(this).closest('td').prev().append($form);
	*/
});

// add TPB search


// add styling
$('head').append(
	$('<style/>').append(' \
	.button-watch {  } \
	tr.watched { background: ' + watched_color + '; }  \
	td.col-filename a { text-decoration: underline; } \
	td.col-filename:hover a { text-decoration: overline; } \
	form.mysearch { display: inline; } \
	form.mysearch button { height: 16px; width: 16px; border: none; } \
	')
);

})();