Created
June 28, 2018 23:09
-
-
Save strayge/47f82ec6be95006777d13691755dbb55 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Hide unwanted streams on Twitch | |
// @description Blocks content that you don't want to see on twitch.tv, such as channels, games, videos etc. | |
// @namespace https://github.com/LinogeFly/hide-unwanted-streams-on-twitch | |
// @version 1.3.29 | |
// @author LinogeFly | |
// @license MIT | |
// @supportURL https://www.reddit.com/message/compose/?to=LinogeFly | |
// @include http://*.twitch.tv/* | |
// @include https://*.twitch.tv/* | |
// @grant GM.getValue | |
// @grant GM.setValue | |
// @grant GM.deleteValue | |
// @run-at document-start | |
// @require https://code.jquery.com/jquery-1.11.2.min.js | |
// @require https://www.promisejs.org/polyfills/promise-6.1.0.min.js | |
// ==/UserScript== | |
// jQuery init (for Greasemonkey) | |
this.$ = this.jQuery = jQuery.noConflict(true); | |
// Constants | |
var husot = husot || {}; | |
husot.constants = husot.constants || {}; | |
husot.constants.blockedChannelsSettingsKey = 'blockedChannels'; | |
husot.constants.blockedGamesSettingsKey = 'blockedGames'; | |
husot.constants.blockedChannelsListEmpty = 'No Blocked Channels'; | |
husot.constants.blockedGamesListEmpty = 'No Blocked Games'; | |
husot.constants.modalDialogShowingSpeed = 150; | |
husot.constants.allowedUrls = [ | |
'^https?://([a-zA-Z]+\.)?twitch.tv/directory/?$', | |
'^https?://([a-zA-Z]+\.)?twitch.tv/directory/all(/?|/.+)$', | |
'^https?://([a-zA-Z]+\.)?twitch.tv/directory/game/.+', | |
'^https?://([a-zA-Z]+\.)?twitch.tv/communities/[^/]+/?$' | |
]; | |
husot.constants.blockedItemType = husot.constants.blockedItemType || {}; | |
husot.constants.blockedItemType.game = 'game'; | |
husot.constants.blockedItemType.channel = 'channel'; | |
// DOM Listener module | |
var husot = husot || {}; | |
husot.domListener = husot.domListener || {}; | |
husot.domListener = (function () { | |
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; | |
var observer = new MutationObserver(function (mutations) { | |
// Don't process page if its URL is not allowed | |
if (!isUrlAllowed(document.URL)) { | |
return; | |
} | |
modifyThumbs(mutations, husot.thumbs.streamThumbsManager); | |
modifyThumbs(mutations, husot.thumbs.gameThumbsManager); | |
}); | |
function start() { | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
} | |
function stop() { | |
observer.disconnect(); | |
} | |
function modifyThumbs(mutations, thumbsManager) { | |
// Process thumbs if they were added to the DOM | |
if (!isThumbsAdded(mutations, thumbsManager.getDomListnerThumbSelector())) { return } | |
// Add overlay menu | |
stop(); | |
thumbsManager.addThumbOverlays(); | |
start(); | |
// Hide blocked thumbs | |
thumbsManager.hideThumbs(); | |
} | |
function isUrlAllowed(url) { | |
return husot.constants.allowedUrls.some(function (item) { | |
return (new RegExp(item)).test(decodeURIComponent(url)); | |
}); | |
} | |
function isThumbsAdded(mutations, selector) { | |
return mutations.some(function (item) { | |
return $(item.addedNodes).find(selector).filter(function () { | |
// Check that thumbnail is hidden explicitly and not because an ancestor element is hidden | |
return $(this).css('display') !== 'none'; | |
}).length !== 0; | |
}); | |
} | |
return { | |
start: start, | |
isUrlAllowed: isUrlAllowed | |
}; | |
})(); | |
// Exceptions | |
var husot = husot || {}; | |
husot.exceptions = husot.exceptions || {}; | |
husot.exceptions.abstractFunctionCall = function () { | |
return 'Cannot call abstract function' | |
}; | |
husot.exceptions.notImplemented = function () { | |
return 'Method or operation is not implemented' | |
}; | |
husot.exceptions.argumentNullOrEmpty = function (argumentName) { | |
return 'Argument "{0}" is undefined or empty'.format(argumentName); | |
}; | |
husot.exceptions.argumentOneElementExpected = function (argumentName) { | |
return 'More than one element in argument "{0}"'.format(argumentName); | |
}; | |
husot.exceptions.elementNotFound = function (elementName) { | |
return '{0} not found. CSS selector must be broken.'.format(elementName); | |
}; | |
husot.exceptions.elementNotFoundFor = function (elementName, forName) { | |
return '{0} not found for {1}. CSS selector must be broken.'.format(elementName, forName); | |
}; | |
// Helper functions | |
if (!String.format) { | |
String.prototype.format = function () { | |
var args = arguments; | |
return this.replace(/{(\d+)}/g, function (match, number) { | |
return typeof args[number] != 'undefined' ? args[number] : match; | |
}); | |
}; | |
}; | |
if (!String.trimSlash) { | |
String.prototype.trimSlash = function () { | |
return this.replace(/^\/|\/$/g, ''); | |
}; | |
}; | |
// HTML Templates | |
// TODO: Move into separate files | |
var husot = husot || {}; | |
husot.htmlLayout = husot.htmlLayout || {}; | |
husot.htmlLayout.streamOverlay = '\ | |
<div class="husot-thumbOverlay">\ | |
<ul class="husot-thumbOverlay-menu">\ | |
<li><a class="husot-blockStreamBtn" href="javascript:void(0);">Block</a></li>\ | |
<li class="husot-thumbOverlay-menu-separator"> | </li>\ | |
<li><a class="husot-showSettingsBtn" href="javascript:void(0);">Settings</a></li>\ | |
</ul>\ | |
</div>'; | |
husot.htmlLayout.settingsWindow = '\ | |
<div class="husot-settings husot-modalWindow">\ | |
<ul class="husot-settings-nav">\ | |
<li class="husot-settings-nav-item">\ | |
<a class="husot-settings-nav-item-name" data-husot-contentPanelId="husot-settings-blockedChannelsList">Blocked Channels</a>\ | |
</li>\ | |
<li class="husot-settings-nav-item">\ | |
<a class="husot-settings-nav-item-name" data-husot-contentPanelId="husot-settings-blockedGamesList">Blocked Games</a>\ | |
</li>\ | |
</ul>\ | |
<ul class="husot-settings-blockedList" id="husot-settings-blockedChannelsList"></ul>\ | |
<ul class="husot-settings-blockedList" id="husot-settings-blockedGamesList"></ul>\ | |
<div class="husot-settings-footer">\ | |
<a href="#" class="husot-modalClose husot-button">Close</a>\ | |
</div>\ | |
</div>'; | |
husot.htmlLayout.modalDialogOverlay = '<div class="husot-modalOverlay"></div>'; | |
husot.htmlLayout.blockedListItem = '\ | |
<li class="husot-settings-blockedList-item">\ | |
<div class="husot-settings-blockedList-item-name">{0}</div>\ | |
<a class="husot-settings-blockedList-item-unblockBtn husot-button" href="javascript:void(0);">Unblock</a>\ | |
</li>'; | |
husot.htmlLayout.blockedListItemEmpty = '<li><div class="husot-settings-blockedList-item-empty">{0}</div></li>'; | |
// Log manager | |
var husot = husot || {}; | |
husot.log = husot.log || {}; | |
husot.log.info = function (obj) { | |
console.log('HUSOT: ' + obj); | |
}; | |
husot.log.error = function (obj) { | |
console.error('HUSOT: ' + obj); | |
}; | |
husot.log.debug = function (obj) { | |
if (typeof husot.debug === 'undefined') { | |
return; | |
} | |
console.log('HUSOT DEBUG: ' + obj); | |
}; | |
// Modal Dialog module | |
var husot = husot || {}; | |
husot.modalDialog = husot.modalDialog || {}; | |
husot.modalDialog = (function () { | |
function initOverlay() { | |
if ($('.husot-modalOverlay').length) { | |
return; | |
} | |
var $overlay = $(husot.htmlLayout.modalDialogOverlay); | |
$overlay.click(close); | |
$(document.body).append($overlay); | |
} | |
function create($modalWindow) { | |
$modalWindow.click(function (event) { | |
event.stopPropagation(); | |
}); | |
$modalWindow.find('.husot-modalClose').click(close); | |
$('.husot-modalOverlay').append($modalWindow); | |
} | |
function show($modalWindow) { | |
$('.husot-modalOverlay').fadeIn(husot.constants.modalDialogShowingSpeed); | |
$modalWindow.fadeIn({ queue: false, duration: husot.constants.modalDialogShowingSpeed }); | |
$modalWindow.animate({ 'margin-top': '40px' }, husot.constants.modalDialogShowingSpeed); | |
} | |
function close(event) { | |
$('.husot-modalOverlay').fadeOut(husot.constants.modalDialogShowingSpeed); | |
var $modalWindow = $('.husot-modalWindow'); | |
$modalWindow.fadeOut(husot.constants.modalDialogShowingSpeed); | |
$modalWindow.animate({ 'margin-top': '50px' }, husot.constants.modalDialogShowingSpeed); | |
} | |
return { | |
initOverlay: initOverlay, | |
create: create, | |
show: show, | |
close: close, | |
}; | |
})(); | |
// Inject javaScript into main window | |
var husot = husot || {}; | |
husot.injector = husot.injector || {}; | |
husot.injector.addScripts = function () { | |
var script = document.createElement('script'); | |
script.textContent = 'document.addEventListener(\"husot.loadMoreThumbs\",function(){$(\"#directory-list\").trigger(\"scroll\")});'; | |
(document.head || document.documentElement).appendChild(script); | |
script.parentNode.removeChild(script); | |
}; | |
// Application settings | |
var husot = husot || {}; | |
husot.settings = husot.settings || {}; | |
husot.settings.BlockedItems = function (settingsKey) { | |
this._settingsKey = settingsKey; | |
this._blockedItems; // For caching | |
}; | |
husot.settings.BlockedItems.prototype = { | |
_get: function (name, callback) { | |
this.list(function (items) { | |
var $item = $.grep(items, function (x) { return x === name; }); | |
if (!$item.length) { | |
callback(); | |
} else { | |
callback($item[0]); | |
} | |
}); | |
}, | |
add: function (name, callback) { | |
var self = this, | |
start = new Date().getTime(); | |
// Initial checks | |
if (typeof name === 'undefined' || name === '') { | |
return; | |
} | |
husot.log.debug('husot.settings.BlockedItems.add() starts'); | |
self._get(name, function (item) { | |
// Don't process if already in the list | |
if (typeof item !== 'undefined') { | |
callback(); | |
return; | |
} | |
// Add to the list | |
self.list(function (items) { | |
items.push(name); | |
husot.settings.setValue(self._settingsKey, JSON.stringify(items), function () { | |
// Invalidate cached list of blocked items | |
self._blockedItems = undefined; | |
husot.log.debug('husot.settings.BlockedItems.add() ends after {0} ms'.format((new Date().getTime()) - start)); | |
callback(); | |
}); | |
}); | |
}); | |
}, | |
remove: function (name, callback) { | |
var self = this; | |
// Initial checks | |
if (typeof name === 'undefined' || name === '') { | |
callback(); | |
return; | |
} | |
this._get(name, function (item) { | |
// Don't process if not in the list | |
if (typeof item === 'undefined') { | |
callback(); | |
return; | |
} | |
// Remove from the list | |
self.list(function (items) { | |
var index = $.inArray(item, items); | |
items.splice(index, 1); | |
husot.settings.setValue(self._settingsKey, JSON.stringify(items), function () { | |
// Invalidate cached list of blocked items | |
self._blockedItems = undefined; | |
callback(); | |
}); | |
}); | |
}); | |
}, | |
list: function (callback) { | |
var self = this, | |
start = new Date().getTime(); | |
if (typeof self._blockedItems === 'undefined') { | |
husot.log.debug('husot.settings.BlockedItems.list() starts'); | |
husot.settings.getValue(self._settingsKey, '[]', function (item) { | |
// Convert to JSON | |
var items = JSON.parse(item); | |
items = items.map(function (x) { | |
// Backward compatibility | |
// Previously, items were stored not as array of strings but as objects with 'name' property. | |
// So trying to fetch 'name' property first. | |
if (typeof x.name !== 'undefined') { | |
return x.name; | |
} | |
return x; | |
}); | |
// Sort by name alphabetically | |
items.sort(function (a, b) { | |
return a.localeCompare(b); | |
}); | |
// Save in cache | |
self._blockedItems = items; | |
husot.log.debug('husot.settings.BlockedItems.list() ends after {0} ms'.format((new Date().getTime()) - start)); | |
// Return | |
if (typeof callback !== 'undefined') { | |
callback(self._blockedItems); | |
} | |
}); | |
} else { | |
if (typeof callback !== 'undefined') { | |
callback(self._blockedItems); | |
} | |
} | |
} | |
}; | |
// Settings UI | |
var husot = husot || {}; | |
husot.settings = husot.settings || {}; | |
husot.settings.ui = husot.settings.ui || {}; | |
// class Tab | |
husot.settings.ui.Tab = function ($blockedList, blockedItemsManager, emptyText, thumbsManager) { | |
this._$blockedList = $blockedList; | |
this._blockedItemsManager = blockedItemsManager; | |
this._emptyText = emptyText; | |
this._thumbsManager = thumbsManager; | |
}; | |
husot.settings.ui.Tab.prototype = (function () { | |
return { | |
_unblockBtn_onClick: function (self, sender) { | |
var $sender = $(sender); | |
var $blockedListItem = $sender.closest('.husot-settings-blockedList-item'); | |
var name = $blockedListItem.find('.husot-settings-blockedList-item-name').text(); | |
self._blockedItemsManager.remove(name, function () { | |
self.loadBlockedItems(); | |
self._thumbsManager.showThumbs(name); | |
}); | |
}, | |
loadBlockedItems: function () { | |
var self = this; | |
this._blockedItemsManager.list(function (items) { | |
self._$blockedList.empty(); | |
if (items.length === 0) { | |
self._$blockedList.append(husot.htmlLayout.blockedListItemEmpty.format(self._emptyText)); | |
return; | |
} | |
items.forEach(function (item) { | |
var $blockedListItem = $(husot.htmlLayout.blockedListItem.format(item)); | |
var $unblockBtn = $('.husot-settings-blockedList-item-unblockBtn', $blockedListItem); | |
$unblockBtn.click(function () { | |
self._unblockBtn_onClick(self, this); | |
}); | |
self._$blockedList.append($blockedListItem); | |
}); | |
}); | |
}, | |
activate: function () { | |
husot.settings.ui.activateTab(this._$blockedList.attr('id')); | |
} | |
} | |
})(); | |
// class Window | |
husot.settings.ui.Window = function () { | |
var create = function () { | |
var $settingsWindow = $(husot.htmlLayout.settingsWindow); | |
$('.husot-settings-nav-item-name', $settingsWindow).click(navItem_onClick); | |
husot.modalDialog.create($settingsWindow); | |
} | |
// Event handlers for switching content of the tabs | |
var navItem_onClick = function () { | |
var tabId = $(this).attr('data-husot-contentPanelId'); | |
husot.settings.ui.activateTab(tabId); | |
} | |
// Class initialization | |
create(); | |
this._blockedChannelsTab = new husot.settings.ui.Tab( | |
$('#husot-settings-blockedChannelsList'), | |
husot.settings.blockedChannels, | |
husot.constants.blockedChannelsListEmpty, | |
husot.thumbs.streamThumbsManager | |
); | |
this._blockedGamesTab = new husot.settings.ui.Tab( | |
$('#husot-settings-blockedGamesList'), | |
husot.settings.blockedGames, | |
husot.constants.blockedGamesListEmpty, | |
husot.thumbs.gameThumbsManager | |
); | |
} | |
husot.settings.ui.Window.prototype = { | |
init: function (blockedItemType) { | |
// Load tab content | |
this._blockedChannelsTab.loadBlockedItems(); | |
this._blockedGamesTab.loadBlockedItems(); | |
// Activate tab | |
if (typeof blockedItemType === 'undefined' || blockedItemType === '') { | |
return; | |
} | |
if (blockedItemType === husot.constants.blockedItemType.channel) { | |
this._blockedChannelsTab.activate(); | |
return; | |
} | |
if (blockedItemType === husot.constants.blockedItemType.game) { | |
this._blockedGamesTab.activate(); | |
return; | |
} | |
throw Error('Unknown blockedItemType'); | |
} | |
} | |
// Helper static functions | |
husot.settings.ui.activateTab = function (tabId) { | |
// Hide all tabs | |
$('.husot-settings-blockedList').hide(); | |
$('.husot-settings-nav-item-name').removeClass('husot-settings-nav-item-name-active'); | |
// Show active tab | |
var $tabHeader = $('.husot-settings-nav-item-name[data-husot-contentPanelId={0}]'.format(tabId)); | |
var $tab = $('#{0}'.format(tabId)); | |
$tab.show(); | |
$tabHeader.addClass('husot-settings-nav-item-name-active'); | |
}; | |
// Video Thumbnails module | |
var husot = husot || {}; | |
husot.thumbs = husot.thumbs || {}; | |
// abstract class ThumbsManagerBase | |
husot.thumbs.ThumbsManagerBase = function () { | |
} | |
husot.thumbs.ThumbsManagerBase.prototype = { | |
_getContainerJQuery: function () { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
_getThumbJQuery: function () { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
_addThumbOverlay: function ($thumb) { | |
var self = this; | |
// Initial checks | |
if ($thumb.find('.husot-thumbOverlay').length) { | |
return; | |
}; | |
// Add overlay | |
var $thumbOverlay = $(husot.htmlLayout.streamOverlay); | |
$thumb.append($thumbOverlay); | |
// Add event handlers for overlay buttons | |
$thumbOverlay.find('.husot-blockStreamBtn').click(function (event) { | |
event.stopPropagation(); | |
}); | |
$thumbOverlay.find('.husot-blockStreamBtn').click(function () { | |
self._blockBtn_onClick(self, this) | |
}); | |
$thumbOverlay.find('.husot-showSettingsBtn').click(function (event) { | |
event.stopPropagation(); | |
}); | |
$thumbOverlay.find('.husot-showSettingsBtn').click(function () { | |
self._showSettingsBtn_onClick(self, this); | |
}); | |
// Add hover event handler to a stream/video thumb in order to hide/show overlay menu | |
$thumb.hover(function () { | |
$thumbOverlay.show(); | |
}, function () { | |
$thumbOverlay.hide(); | |
}); | |
}, | |
_blockBtn_onClick: function (self, sender) { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
_showSettingsBtn_onClick: function (self, sender) { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
// Triggers "infinite scroll" feature on Twitch to load more stream/video thumbnails | |
// in order to make sure that page it is filled with new thumbnails after some thumbnails were hidden. | |
_loadMoreThumbs: function () { | |
husot.log.debug('Triggering "infinite scroll" to load more thumbs'); | |
// Raise injected custom event that triggers "infinite scroll" feature on Twitch. | |
var event = document.createEvent('Event'); | |
event.initEvent('husot.loadMoreThumbs', true, true); | |
document.dispatchEvent(event); | |
}, | |
_notifyAboutHiddenThumbs: function (count) { | |
// Initial checks | |
if (count === 0) { return } | |
husot.log.info('{0} thumbnail{1} {2} hidden'.format( | |
count, | |
(count > 1 ? 's' : ''), | |
(count > 1 ? 'were' : 'was') | |
)); | |
}, | |
_notifyAboutShownThumbs: function (count) { | |
// Initial checks | |
if (count === 0) { return } | |
husot.log.info('{0} thumbnail{1} {2} shown'.format( | |
count, | |
(count > 1 ? 's' : ''), | |
(count > 1 ? 'were' : 'was') | |
)); | |
}, | |
getDomListnerThumbSelector: function () { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
addThumbOverlays: function () { | |
var self = this; | |
// Initial checks | |
var $thumbs = self._getThumbJQuery(); | |
if (!$thumbs.length) { return; } | |
$thumbs.each(function () { | |
self._addThumbOverlay($(this)); | |
}); | |
}, | |
hideThumbs: function () { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
}, | |
showThumbs: function (name) { | |
throw Error(husot.exceptions.abstractFunctionCall()); | |
} | |
}; | |
// class StreamThumbsManager: ThumbsManagerBase | |
husot.thumbs.StreamThumbsManager = function () { | |
husot.thumbs.ThumbsManagerBase.call(this); | |
} | |
husot.thumbs.StreamThumbsManager.prototype = Object.create(husot.thumbs.ThumbsManagerBase.prototype); | |
husot.thumbs.StreamThumbsManager.prototype.constructor = husot.thumbs.StreamThumbsManager; | |
husot.thumbs.StreamThumbsManager.prototype.getDomListnerThumbSelector = function () { | |
return '[data-test-selector="preview-card-titles__primary-link"]'; | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getContainerJQuery = function () { | |
return $('[data-target="directory-game__card_container"]').parent(); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getThumbJQuery = function () { | |
return $('[data-target="directory-game__card_container"]').find('figure:first'); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getGameName = function ($thumbContainer) { | |
var self = this; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
var $game = $thumbContainer.find('a[href*="/game/"]') | |
.filter(function () { | |
// Check that game thumbnail is hidden explicitly and not because an ancestor element is hidden | |
return $(this).css('display') !== 'none'; | |
}); | |
if (!$game.length) { | |
return ''; | |
} | |
return $game.text().trim(); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getChannelName = function ($thumbContainer) { | |
var self = this; | |
var map = [ | |
{ | |
urls: [ | |
'^https?://([a-zA-Z]+\.)?twitch.tv/directory/all(/?|/.+)$' | |
], | |
name: function () { | |
return $thumbContainer.find('[data-test-selector="preview-card-titles__primary-link"]').attr('href').trimSlash(); | |
} | |
}, | |
// Default (should be the last one) | |
{ | |
name: function() { | |
return $thumbContainer.find('[data-test-selector="preview-card-titles__primary-link"]').attr('href').trimSlash(); | |
} | |
} | |
]; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
return self._getChannelNameForUrl(map); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getChannelNameForUrl = function (map) { | |
var result; | |
map.forEach(function (item) { | |
if (result) { // Selector has been found already | |
return; | |
}; | |
if (!item.urls) { // Gets default selector that doesn't have URLs | |
result = item.name(); | |
return; | |
}; | |
var isMatch = item.urls.some(function (url) { | |
return (new RegExp(url)).test(decodeURIComponent(document.URL)); | |
}); | |
if (isMatch) { | |
result = item.name(); | |
return; | |
} | |
}); | |
if (typeof result === 'undefined') { | |
throw Error('CSS selector for "Channel name" not found.'); | |
} | |
return result; | |
} | |
husot.thumbs.StreamThumbsManager.prototype._showSettingsBtn_onClick = function (self, sender) { | |
husot.settings.ui.window.init(husot.constants.blockedItemType.channel); | |
husot.modalDialog.show($('.husot-settings')); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._blockBtn_onClick = function (self, sender) { | |
var $sender = $(sender); | |
var $thumbContainer = $sender.closest(self._getContainerJQuery()); | |
// Initial checks | |
if (!$thumbContainer.length) { | |
throw Error(husot.exceptions.elementNotFound('Thumb container')); | |
}; | |
var name = self._getChannelName($thumbContainer); | |
husot.settings.blockedChannels.add(name, function () { | |
self._hideThumbs(name); | |
self._loadMoreThumbs(); | |
}); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._hideThumbs = function (name) { | |
var self = this; | |
var $thumbContainers = self._getThumbContainersForChannel(name).filter(':visible'); | |
// Initial checks | |
if (!$thumbContainers.length) { | |
throw Error(husot.exceptions.elementNotFoundFor('Thumb container', '"{0}" channel'.format(name))); | |
}; | |
$thumbContainers.hide(); | |
self._notifyAboutHiddenThumbs($thumbContainers.length); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getThumbContainersForChannel = function (name) { | |
var self = this; | |
var $thumbContainers = self._getContainerJQuery(); | |
// No stream thumbs on the page | |
if (!$thumbContainers.length) { | |
return $(); | |
} | |
return $thumbContainers.filter(function () { | |
var $this = $(this); | |
var channelName = self._getChannelName($this); | |
return channelName.toLowerCase() === name.toLowerCase(); | |
}); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._getThumbContainersForGame = function (name) { | |
var self = this; | |
var $thumbContainers = self._getContainerJQuery(); | |
// No stream thumbs on the page | |
if (!$thumbContainers.length) { | |
return $(); | |
} | |
return $thumbContainers.filter(function () { | |
var $this = $(this); | |
var gameName = self._getGameName($this); | |
return gameName.toLowerCase() === name.toLowerCase(); | |
}); | |
} | |
husot.thumbs.StreamThumbsManager.prototype._isThumbMustBeHiddenForChannel = function ($thumbContainer, blockedChannels) { | |
var self = this; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
if ($thumbContainer.length !== 1) { | |
throw Error(husot.exceptions.argumentOneElementExpected('$thumbContainer')); | |
} | |
var channelName = self._getChannelName($thumbContainer); | |
return blockedChannels.some(function (item) { | |
return channelName.toLowerCase() === item.toLowerCase(); | |
}); | |
}; | |
husot.thumbs.StreamThumbsManager.prototype._isThumbMustBeHiddenForGame = function ($thumbContainer, blockedGames) { | |
var self = this; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
if ($thumbContainer.length !== 1) { | |
throw Error(husot.exceptions.argumentOneElementExpected('$thumbContainer')); | |
} | |
var gameName = self._getGameName($thumbContainer); | |
if (typeof gameName === 'undefined' || gameName === '') { // Game name is optional in this manager | |
return false; | |
} | |
return blockedGames.some(function (item) { | |
return gameName.toLowerCase() === item.toLowerCase(); | |
}); | |
}; | |
husot.thumbs.StreamThumbsManager.prototype.hideThumbs = function () { | |
var self = this; | |
var start = new Date().getTime(); | |
husot.log.debug('StreamThumbsManager.hideThumbs() starts'); | |
// Load block lists for channels and games | |
var blockedChannelsPromise = new Promise(function (resolve, reject) { | |
husot.settings.blockedChannels.list(function (items) { | |
resolve(items); | |
}); | |
}); | |
var blockedGamesPromise = new Promise(function (resolve, reject) { | |
husot.settings.blockedGames.list(function (items) { | |
resolve(items); | |
}); | |
}); | |
// Hide thumbnails after block lists are loaded | |
Promise.all([blockedChannelsPromise, blockedGamesPromise]).then(function (values) { | |
var blockedChannels = values[0]; | |
var blockedGames = values[1]; | |
// Get visible thumbs | |
$thumbContainers = self._getContainerJQuery().filter(':visible'); | |
// Enumerate visible thumbs and hide those that must be hidden | |
var hiddenThumbsCount = 0; | |
$thumbContainers.each(function () { | |
var $item = $(this); | |
// Hide for channels | |
if (self._isThumbMustBeHiddenForChannel($item, blockedChannels)) { | |
$item.hide(); | |
hiddenThumbsCount++; | |
return; | |
} | |
// Hide for games | |
if (self._isThumbMustBeHiddenForGame($item, blockedGames)) { | |
$item.hide(); | |
hiddenThumbsCount++; | |
return; | |
} | |
}); | |
if (hiddenThumbsCount > 0) { | |
self._notifyAboutHiddenThumbs(hiddenThumbsCount); | |
self._loadMoreThumbs(); | |
} | |
husot.log.debug('StreamThumbsManager.hideThumbs() ends after {0} ms'.format((new Date().getTime()) - start)); | |
}); | |
} | |
husot.thumbs.StreamThumbsManager.prototype.showThumbs = function (name) { | |
var self = this; | |
var $thumbContainers = self._getThumbContainersForChannel(name).filter(':hidden'); | |
// Initial checks | |
if (!$thumbContainers.length) { return }; | |
new Promise(function (resolve, reject) { // Load block list for games | |
husot.settings.blockedGames.list(function (items) { | |
resolve(items); | |
}); | |
}) | |
.then(function (blockedGames) { // Show thumbnails after block list is loaded | |
var shownThumbsCount = 0; | |
$thumbContainers.each(function () { | |
var $item = $(this); | |
// Don't hide if game is in the block list | |
if (self._isThumbMustBeHiddenForGame($item, blockedGames)) { return } | |
$item.show(); | |
shownThumbsCount++; | |
}); | |
self._notifyAboutShownThumbs(shownThumbsCount); | |
}); | |
} | |
husot.thumbs.StreamThumbsManager.prototype.showThumbsForGame = function (name) { | |
var self = this; | |
var $thumbContainers = self._getThumbContainersForGame(name).filter(':hidden'); | |
// Initial checks | |
if (!$thumbContainers.length) { return }; | |
new Promise(function (resolve, reject) { // Load block list for channels | |
husot.settings.blockedChannels.list(function (items) { | |
resolve(items); | |
}); | |
}) | |
.then(function (blockedChannels) { // Show thumbnails after block list is loaded | |
var shownThumbsCount = 0; | |
$thumbContainers.each(function () { | |
var $item = $(this); | |
// Don't hide if channel is in the block list | |
if (self._isThumbMustBeHiddenForChannel($item, blockedChannels)) { return } | |
$item.show(); | |
shownThumbsCount++; | |
}); | |
self._notifyAboutShownThumbs(shownThumbsCount); | |
}); | |
} | |
// class GameThumbsManager: ThumbsManagerBase | |
husot.thumbs.GameThumbsManager = function (streamThumbsManager) { | |
husot.thumbs.ThumbsManagerBase.call(this); | |
this._streamThumbsManager = streamThumbsManager; | |
} | |
husot.thumbs.GameThumbsManager.prototype = Object.create(husot.thumbs.ThumbsManagerBase.prototype); | |
husot.thumbs.GameThumbsManager.prototype.constructor = husot.thumbs.GameThumbsManager; | |
husot.thumbs.GameThumbsManager.prototype.getDomListnerThumbSelector = function () { | |
return '[data-target="directory-page__card-container"]'; | |
} | |
husot.thumbs.GameThumbsManager.prototype._getContainerJQuery = function () { | |
return $('[data-target="directory-page__card-container"]').parent(); | |
} | |
husot.thumbs.GameThumbsManager.prototype._getThumbJQuery = function () { | |
return $('[data-target="directory-page__card-container"]').find('figure:first'); | |
} | |
husot.thumbs.GameThumbsManager.prototype._getGameName = function($thumbContainer) { | |
var self = this; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
var $game = $thumbContainer.find('.tw-card-body .tw-box-art-card__title'); | |
if (!$game.length) { | |
throw Error(husot.exceptions.elementNotFound('Game name')); | |
} | |
return $game.text().trim(); | |
} | |
husot.thumbs.GameThumbsManager.prototype._showSettingsBtn_onClick = function (self, sender) { | |
husot.settings.ui.window.init(husot.constants.blockedItemType.game); | |
husot.modalDialog.show($('.husot-settings')); | |
} | |
husot.thumbs.GameThumbsManager.prototype._blockBtn_onClick = function (self, sender) { | |
var $sender = $(sender); | |
var $thumbContainer = $sender.closest(self._getContainerJQuery()); | |
// Initial checks | |
if (!$thumbContainer.length) { | |
throw Error(husot.exceptions.elementNotFound('Thumb container')); | |
}; | |
var name = self._getGameName($thumbContainer); | |
husot.settings.blockedGames.add(name, function () { | |
self._hideThumbs(name); | |
self._loadMoreThumbs(); | |
}); | |
} | |
husot.thumbs.GameThumbsManager.prototype._hideThumbs = function (name) { | |
var self = this; | |
var $thumbContainer = self._getThumbContainer(name).filter(':visible'); | |
// Initial checks | |
if (!$thumbContainer.length) { | |
throw Error(husot.exceptions.elementNotFoundFor('Thumb container', '"{0}" game'.format(name))); | |
}; | |
$thumbContainer.hide(); | |
self._notifyAboutHiddenThumbs($thumbContainer.length); | |
} | |
husot.thumbs.GameThumbsManager.prototype._getThumbContainer = function (name) { | |
var self = this; | |
var $thumbContainers = self._getContainerJQuery(); | |
// No game thumbs on the page | |
if (!$thumbContainers.length) { | |
return $(); | |
} | |
return $thumbContainers.filter(function () { | |
var $this = $(this); | |
var gameName = self._getGameName($this); | |
return gameName.toLowerCase() === name.toLowerCase(); | |
}); | |
} | |
husot.thumbs.GameThumbsManager.prototype._isThumbMustBeHidden = function ($thumbContainer, blockedGames) { | |
var self = this; | |
// Initial checks | |
if (typeof $thumbContainer === 'undefined' || !$thumbContainer.length) { | |
throw Error(husot.exceptions.argumentNullOrEmpty('$thumbContainer')); | |
} | |
if ($thumbContainer.length !== 1) { | |
throw Error(husot.exceptions.argumentOneElementExpected('$thumbContainer')); | |
} | |
var name = self._getGameName($thumbContainer); | |
return blockedGames.some(function (item) { | |
return name.toLowerCase() === item.toLowerCase(); | |
}); | |
}; | |
husot.thumbs.GameThumbsManager.prototype._showThumbs = function (name) { | |
var self = this; | |
var $thumbContainer = self._getThumbContainer(name).filter(':hidden'); | |
// Initial checks | |
if (!$thumbContainer.length) { return }; | |
$thumbContainer.show(); | |
self._notifyAboutShownThumbs($thumbContainer.length); | |
}; | |
husot.thumbs.GameThumbsManager.prototype.hideThumbs = function () { | |
var self = this; | |
var start = new Date().getTime(); | |
husot.log.debug('GameThumbsManager.hideThumbs() starts'); | |
new Promise(function (resolve, reject) { // Load blocked list for games | |
husot.settings.blockedGames.list(function (items) { | |
resolve(items); | |
}); | |
}) | |
.then(function (blockedGames) { // Hide thumbnails after block list is loaded | |
// Get visible thumbs | |
$thumbContainers = self._getContainerJQuery().filter(':visible'); | |
// Enumerate visible thumbs and hide those that must be hidden | |
var hiddenThumbsCount = 0; | |
$thumbContainers.each(function () { | |
var $item = $(this); | |
// Hide game if needed | |
if (self._isThumbMustBeHidden($item, blockedGames)) { | |
$item.hide(); | |
hiddenThumbsCount++; | |
} | |
}); | |
if (hiddenThumbsCount > 0) { | |
self._notifyAboutHiddenThumbs(hiddenThumbsCount); | |
self._loadMoreThumbs(); | |
} | |
husot.log.debug('GameThumbsManager.hideThumbs() ends after {0} ms'.format((new Date().getTime()) - start)); | |
}); | |
}; | |
husot.thumbs.GameThumbsManager.prototype.showThumbs = function (name) { | |
var self = this; | |
self._showThumbs(name); | |
self._streamThumbsManager.showThumbsForGame(name); | |
}; | |
// Embedded CSS styles | |
(function () { | |
// Run only in top frame | |
if (window.top !== window.self) { | |
return; | |
} | |
var style = document.createElement('style'); | |
style.textContent = '.husot-button{background:#6441a5;color:#fff;padding:0 10px;font-size:12px;text-align:center;cursor:pointer;height:30px;display:inline-block;line-height:30px}.husot-button:hover{color:#fff;background:#7550ba;text-decoration:none}.husot-modalOverlay{display:none;background:rgba(33,18,51,.9);position:fixed;z-index:10000;top:0;bottom:0;left:0;padding:20px 0;width:100%;overflow-x:hidden;overflow-y:auto}.husot-modalWindow{display:none;position:relative;opacity:1;margin:50px auto 0}.husot-settings{font:12px "Helvetica Neue",Helvetica,Arial,sans-serif;color:#32323e;width:360px;background:#FFF;padding:20px}.husot-settings-nav{list-style:none;padding:0;margin:0 0 5px;border-bottom:1px solid rgba(0,0,0,.2);overflow:auto}.husot-settings-nav-item{float:left;margin-right:20px}.husot-settings-nav-item-name{font-size:14px;line-height:24px;padding-bottom:7px;display:inline-block;cursor:pointer;text-decoration:none;color:#6441a5;border-bottom:1px solid transparent}.husot-settings-nav-item-name:hover{color:#19191f;border-bottom:1px solid rgba(0,0,0,.35);text-decoration:none}.husot-settings-nav-item-name-active,.husot-settings-nav-item-name-active:hover{color:#19191f;border-bottom:1px solid #19191f}.husot-settings-blockedList{list-style:none;padding:0;margin:0 0 5px;overflow-y:auto;min-height:240px;max-height:400px}.husot-settings-blockedList-item{margin:5px 0;clear:both;overflow:auto}.husot-settings-blockedList-item-name{font-size:14px;display:inline-block;width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;height:30px;float:left;line-height:30px;padding-right:80px}.husot-settings-blockedList-item-empty{text-align:center;font-size:16px;color:#bbb;font-style:italic;padding:20px 0}.husot-settings-blockedList-item-unblockBtn{float:right;max-width:80px;overflow:hidden;margin-left:-80px}.husot-settings-footer{text-align:center;width:100%;margin:0 0 5px;padding:20px 0 0;border-top:1px solid #dedede}.husot-settings-footer .husot-button{min-width:70px}.husot-thumbOverlay{display:none;position:absolute;top:1rem!important;right:1rem!important;bottom:auto!important;left:auto!important;color:#fff;background-color:rgba(0,0,0,.6);padding:0 5px;border-radius:2px;font:12px "Helvetica Neue",Helvetica,Arial,sans-serif;line-height:18px;width:auto!important;min-height:auto!important}.husot-thumbOverlay a{color:#fff!important;text-decoration:none!important}.husot-thumbOverlay a:hover{color:#fff!important;text-decoration:underline!important}.husot-thumbOverlay-menu{list-style:none;padding:0;margin:0}.husot-thumbOverlay-menu li,.husot-thumbOverlay-menu-separator{display:inline}'; | |
(document.head || document.documentElement).appendChild(style); | |
})(); | |
// Application settings (Userscript specific) | |
var husot = husot || {}; | |
husot.settings = husot.settings || {}; | |
husot.settings.setValue = function (key, value, callback) { | |
GM.setValue(key, value).then(function () { | |
callback(); | |
}, function (reason) { // rejection | |
husot.log.error(reason); | |
}); | |
}; | |
husot.settings.getValue = function (key, defaultValue, callback) { | |
GM.getValue(key).then(function (value) { | |
if (typeof value === 'undefined' || value === '') { | |
callback(defaultValue); | |
} | |
callback(value); | |
}, function (reason) { // rejection | |
husot.log.error(reason); | |
}); | |
}; | |
// Application start | |
var husot = husot || {}; | |
husot.main = function () { | |
// Run only in top frame | |
if (window.top !== window.self) { | |
return; | |
} | |
husot.settings.blockedChannels = new husot.settings.BlockedItems(husot.constants.blockedChannelsSettingsKey); | |
husot.settings.blockedChannels.list(); // Warm up settings so by the hiding time they will be loaded, most likely | |
husot.settings.blockedGames = new husot.settings.BlockedItems(husot.constants.blockedGamesSettingsKey); | |
husot.settings.blockedGames.list(); // Warm up settings so by the hiding time they will be loaded, most likely | |
husot.thumbs.streamThumbsManager = new husot.thumbs.StreamThumbsManager(); | |
husot.thumbs.gameThumbsManager = new husot.thumbs.GameThumbsManager(husot.thumbs.streamThumbsManager); | |
husot.modalDialog.initOverlay(); | |
husot.settings.ui.window = new husot.settings.ui.Window(); | |
husot.injector.addScripts(); | |
husot.domListener.start(); | |
}; | |
$(document).ready(function () { | |
husot.main(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment