您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various search filters and user experience enhancers
当前为
// ==UserScript== // @name Hitomi - Search & UI Tweaks // @namespace brazenvoid // @version 5.2.1 // @author brazenvoid // @license GPL-3.0-only // @description Various search filters and user experience enhancers // @match https://hitomi.la/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js // @require https://greasyfork.org/scripts/375557-base-brazen-resource/code/Base%20Brazen%20Resource.js?version=1115796 // @require https://greasyfork.org/scripts/416104-brazen-ui-generator/code/Brazen%20UI%20Generator.js?version=1115813 // @require https://greasyfork.org/scripts/418665-brazen-configuration-manager/code/Brazen%20Configuration%20Manager.js?version=1114733 // @require https://greasyfork.org/scripts/429587-brazen-item-attributes-resolver/code/Brazen%20Item%20Attributes%20Resolver.js?version=1139392 // @require https://greasyfork.org/scripts/416105-brazen-base-search-enhancer/code/Brazen%20Base%20Search%20Enhancer.js?version=1139379 // @grant GM_addStyle // @run-at document-end // ==/UserScript== GM_addStyle( `#settings-wrapper{font-family:Open Sans;font-size:12px;font-weight:700;line-height:1;background-color:rgb(216, 210, 234);top:5vh;width:320px} #settings-wrapper button{font-family:Open Sans;font-size:12px;font-weight:700} #settings-wrapper textarea.form-input{height:25vh;line-height:2;overflow:auto;padding:0 10px;resize:vertical;white-space:pre;width:92%} #settings-wrapper .font-secondary{color:black} .bg-brand{background-color:rgb(216, 210, 234)} .blacklisted{background-color:lightcoral!important}.blacklisted:hover{background-color:indianred!important} .blacklisted.favourite{background-color:orange!important}.blacklisted.favourite:hover{background-color:darkorange!important} .favourite{background-color:mediumseagreen!important}.favourite:hover{background-color:forestgreen!important}`) const IS_GALLERY_PAGE = $('#dl-button').length const FILTER_GALLERY_TYPES = 'Show Gallery Types' const FILTER_PAGES = 'Pages' const FILTER_TAG_BLACKLIST = 'Tag Blacklist' const FILTER_LANGUAGES = 'Languages' const ENABLE_BLACKLIST = 'Enable Blacklist' const HIGHLIGHT_BLACKLISTED_TAGS = 'Highlight Blacklisted Tags' const OPTION_REMOVE_RELATED_GALLERIES = 'Remove Related Galleries' const UI_FAVOURITE_TAGS = 'Favourite Tags' const UI_SHOW_ALL_TAGS = 'Show All Gallery Tags' class HitomiSearchAndUITweaks extends BrazenBaseSearchEnhancer { constructor() { super({ isUserLoggedIn: false, itemDeepAnalysisSelector: '', itemLinkSelector: '', itemListSelectors: '.gallery-content', itemNameSelector: 'h1.lillie a', itemSelectors: '.acg,.anime,.cg,.dj,.manga', requestDelay: 0, scriptPrefix: 'hitomi-sui-', }) this._configurationManager .addCheckboxesGroup(FILTER_GALLERY_TYPES, [ ['Anime', 'anime'], ['Artist CG', 'acg'], ['Doujinshi', 'dj'], ['Game CG', 'cg'], ['Manga', 'manga'], ], 'Show only selected gallery types.') .addCheckboxesGroup(FILTER_LANGUAGES, [ ['N/A', 'not-applicable'], ['Japanese', 'japanese'], ['Chinese', 'chinese'], ['English', 'english'], ['Albanian', 'albanian'], ['Arabic', 'arabic'], ['Bulgarian', 'bulgarian'], ['Catalan', 'catalan'], ['Cebuano', 'cebuano'], ['Czech', 'czech'], ['Danish', 'danish'], ['Dutch', 'dutch'], ['Esperanto', 'esperanto'], ['Estonian', 'estonian'], ['Finnish', 'finnish'], ['French', 'french'], ['German', 'german'], ['Greek', 'greek'], ['Hebrew', 'hebrew'], ['Hungarian', 'hungarian'], ['Indonesian', 'indonesian'], ['Italian', 'italian'], ['Korean', 'korean'], ['Latin', 'latin'], ['Mongolian', 'mongolian'], ['Norwegian', 'norwegian'], ['Persian', 'persian'], ['Polish', 'polish'], ['Portuguese', 'portuguese'], ['Romanian', 'romanian'], ['Russian', 'russian'], ['Slovak', 'slovak'], ['Spanish', 'spanish'], ['Swedish', 'swedish'], ['Tagalog', 'tagalog'], ['Thai', 'thai'], ['Turkish', 'turkish'], ['Ukrainian', 'ukrainian'], ['Unspecified', 'unspecified'], ['Vietnamese', 'vietnamese'], ], 'Select languages to show') .addFlagField(ENABLE_BLACKLIST, 'Applies the blacklist.') .addFlagField(HIGHLIGHT_BLACKLISTED_TAGS, 'Highlights blacklisted tags. Only works with a disabled blacklist.') .addFlagField(OPTION_REMOVE_RELATED_GALLERIES, 'Remove related galleries section from gallery pages.') .addFlagField(UI_SHOW_ALL_TAGS, 'Show all gallery tags in search results.') .addRangeField(FILTER_PAGES, 0, Infinity, 'Close gallery pages that don\'t satisfy these page limits. Only works on galleries opened in new tabs.') .addRulesetField( FILTER_TAG_BLACKLIST, 10, 'Specify the tags blacklist with one rule on each line. While single tags can be specified, complex multi-tag rules with & (AND) and | (OR) can also be defined.', null, null, (blacklistedTags) => this._optimizeBlacklistRules(blacklistedTags)) .addRulesetField( UI_FAVOURITE_TAGS, 10, 'Specify favourite tags that get highlighted in search results.', null, null, (favouriteTags) => this._optimizeFavouriteRules(favouriteTags)) this._onFirstHitAfterCompliance = (item) => { this._highlightFavouriteTags(item) this._performComplexFlaggedOperation( HIGHLIGHT_BLACKLISTED_TAGS, () => !this._getConfig(ENABLE_BLACKLIST), () => this._highlightBlacklistedTags(item)) this._performComplexFlaggedOperation(UI_SHOW_ALL_TAGS, () => !IS_GALLERY_PAGE, () => this._showAllTags(item)) } this._setupUI() this._setupComplianceFilters() } /** * @private */ _checkPageLimits() { let range = this._getConfig(FILTER_PAGES) if (range.minimum > 0 || range.maximum > 0) { let navPages = $('.simplePagerNav li').length let pageCount = navPages > 0 ? navPages * 50 : $('.simplePagerPage1').length if (!Validator.isInRange(pageCount, range.minimum, range.maximum)) { top.close() } } } /** * @param {string} tag * @return {JQuery.Selector} * @private */ _formatTagSelector(tag) { let selector tag = encodeURIComponent(tag.trim()) if (tag.startsWith('artist%3A')) { selector = 'a[href="/artist/' + tag.replace('artist%3A', '') + '-all.html"]' } else if (tag.startsWith('series%3A')) { selector = 'a[href="/series/' + tag.replace('series%3A', '') + '-all.html"]' } else { selector = 'a[href="/tag/' + tag + '-all.html"]' } return selector } /** * @param {string[][]} ruleset * @param {string[]} tags * @return {string[][]} * @private */ _growBlacklistRuleset(ruleset, tags) { let grownRuleset = [] for (let tag of tags) { for (let rule of ruleset) { grownRuleset.push([...rule, this._formatTagSelector(tag)]) } } return grownRuleset } /** * @param {JQuery} item * @private */ _highlightBlacklistedTags(item) { let isBlacklisted for (let rule of this._configurationManager.getField(FILTER_TAG_BLACKLIST).optimized) { isBlacklisted = true for (let tagSelector of rule) { if (item.find(tagSelector).length === 0) { isBlacklisted = false break } } if (isBlacklisted) { for (let tagSelector of rule) { item.find(tagSelector).addClass('blacklisted') } } } } /** * @param {JQuery} item * @private */ _highlightFavouriteTags(item) { let favouriteTags = this._configurationManager.getField(UI_FAVOURITE_TAGS) if (favouriteTags.optimized.length) { for (let tagSelector of favouriteTags.optimized) { item.find(tagSelector).addClass('favourite') } } } /** * @return {Array} * @private */ _optimizeBlacklistRules(blacklistedRules) { let orTags, iteratedRuleset let optimizedRuleset = [] // Translate user defined rules for (let blacklistedRule of blacklistedRules) { iteratedRuleset = [] for (let andTag of blacklistedRule.split('&')) { orTags = andTag.split('|') if (orTags.length === 1) { this._updateBlacklistRuleset(iteratedRuleset, andTag) } else { if (iteratedRuleset.length) { iteratedRuleset = this._growBlacklistRuleset(iteratedRuleset, orTags) } else { this._updateBlacklistRuleset(iteratedRuleset, orTags) } } } optimizedRuleset = optimizedRuleset.concat(iteratedRuleset) } // Sort rules by complexity return optimizedRuleset.sort((a, b) => a.length - b.length) } /** * @return {Array} * @private */ _optimizeFavouriteRules(favouriteRules) { let rules = [] for (let tag of favouriteRules) { rules.push(this._formatTagSelector(tag)) } return rules } /** * @private */ _setupComplianceFilters() { this._addItemComplianceFilter(FILTER_LANGUAGES, (item, valueKeys) => { let languageLink = item.find('tr:nth-child(3) > td:nth-child(2) a') if (languageLink.length) { languageLink = languageLink.attr('href') for (let key of valueKeys) { if (languageLink.includes(key)) { return true } } return false } return valueKeys.includes('not-applicable') }) this._addItemComplianceFilter(FILTER_GALLERY_TYPES, (item, valueKeys) => { for (let galleryClass of valueKeys) { if (item.hasClass(galleryClass)) { return true } } return false }) this._addItemComplexComplianceFilter( FILTER_TAG_BLACKLIST, (rules) => this._getConfig(ENABLE_BLACKLIST) && rules.length, (item, blacklistRuleset) => { let isBlacklisted for (let rule of blacklistRuleset) { isBlacklisted = true for (let tagSelector of rule) { if (item.find(tagSelector).length === 0) { isBlacklisted = false break } } if (isBlacklisted) { return false } } return true }, ) } /** * @private */ _setupUI() { this._onBeforeUIBuild = () => { if (IS_GALLERY_PAGE) { this._checkPageLimits() this._performFlaggedOperation(OPTION_REMOVE_RELATED_GALLERIES, () => $('.gallery-content').remove()) let tagsSection = $('.tags') this._highlightFavouriteTags(tagsSection) this._performComplexFlaggedOperation( HIGHLIGHT_BLACKLISTED_TAGS, () => !this._getConfig(ENABLE_BLACKLIST), () => this._highlightBlacklistedTags(tagsSection)) } } this._onUIBuild = () => this._uiGen.createSettingsSection().append([ this._uiGen.createTabsSection(['Filters', 'Highlights', 'Languages', 'Global', 'Stats'], [ this._uiGen.createTabPanel('Filters', true).append([ this._configurationManager.createElement(FILTER_GALLERY_TYPES), this._uiGen.createSeparator(), this._configurationManager.createElement(FILTER_PAGES), this._uiGen.createSeparator(), this._configurationManager.createElement(ENABLE_BLACKLIST), this._configurationManager.createElement(FILTER_TAG_BLACKLIST), this._uiGen.createSeparator(), this._configurationManager.createElement(OPTION_DISABLE_COMPLIANCE_VALIDATION), ]), this._uiGen.createTabPanel('Highlights').append([ this._configurationManager.createElement(HIGHLIGHT_BLACKLISTED_TAGS), this._configurationManager.createElement(UI_FAVOURITE_TAGS), ]), this._uiGen.createTabPanel('Languages').append([ this._configurationManager.createElement(FILTER_LANGUAGES), ]), this._uiGen.createTabPanel('Global').append([ this._configurationManager.createElement(UI_SHOW_ALL_TAGS), this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE), this._uiGen.createSeparator(), this._createSettingsBackupRestoreFormActions(), ]), this._uiGen.createTabPanel('Stats').append([ this._uiGen.createStatisticsFormGroup(FILTER_GALLERY_TYPES), this._uiGen.createStatisticsFormGroup(FILTER_LANGUAGES), this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST), this._uiGen.createSeparator(), this._uiGen.createStatisticsTotalsGroup(), ]), ]), this._createSettingsFormActions(), this._uiGen.createSeparator(), this._uiGen.createStatusSection(), ]) this._onAfterUIBuild = () => { this._uiGen.getSelectedSection()[0].userScript = this } } /** * @param {JQuery} item * @private */ _showAllTags(item) { let tags = item.find('.relatedtags > ul > li') let lastTag = tags.last() if (lastTag.text() === '...') { lastTag.remove() tags.find('.hidden-list-item').removeClass('hidden-list-item') } } /** * @param {string[][]} ruleset * @param {string|string[]} tagToAdd * @private */ _updateBlacklistRuleset(ruleset, tagToAdd) { if (ruleset.length) { for (let rule of ruleset) { rule.push(this._formatTagSelector(tagToAdd)) } } else { let tags = typeof tagToAdd === 'string' ? [tagToAdd] : tagToAdd for (let tag of tags) { ruleset.push([this._formatTagSelector(tag)]) } } } } (new HitomiSearchAndUITweaks).init()