您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Numerous features to enrich your browsing experience
当前为
// ==UserScript== // @name E-Hentai - UX Tweaks // @namespace brazenvoid // @version 1.3.3 // @author brazenvoid // @license GPL-3.0-only // @description Numerous features to enrich your browsing experience // @match https://e-hentai.org/* // @match https://exhentai.org/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js // @require https://greasyfork.org/scripts/375557-base-brazen-resource/code/Base%20Brazen%20Resource.js?version=1244990 // @require https://greasyfork.org/scripts/416104-brazen-ui-generator/code/Brazen%20UI%20Generator.js?version=1273726 // @require https://greasyfork.org/scripts/418665-brazen-configuration-manager/code/Brazen%20Configuration%20Manager.js?version=1245040 // @require https://greasyfork.org/scripts/429587-brazen-item-attributes-resolver/code/Brazen%20Item%20Attributes%20Resolver.js?version=1244644 // @require https://greasyfork.org/scripts/416105-brazen-base-search-enhancer/code/Brazen%20Base%20Search%20Enhancer.js?version=1272592 // @grant GM_addStyle // @run-at document-end // ==/UserScript== GM_addStyle( `#settings-wrapper{min-width:300px;width:300px}.disliked-tag{background-color:lightcoral !important;color:white !important}.disliked-tag:hover{background-color:indianred !important}.disliked-tag > a{color:white !important}.disliked-tag.favourite-tag{background-color:orange !important}.disliked-tag.favourite-tag:hover{background-color:darkorange !important}.favourite-tag{background-color:mediumseagreen !important;color:white !important}.favourite-tag:hover{background-color:forestgreen !important}.favourite-tag > a{color:white !important}`) const IS_GALLERY_PAGE = $('#gdt').length const IS_SEARCH_PAGE = $('#f_search').length const IS_SMALL_WINDOW = $('.stuffbox').length const UI_DEFAULTS_PAGE_RANGE = 'Page Range' const UI_DEFAULTS_PAGE_RANGE_ENABLE = 'Enable Page Range Filter' const UI_DEFAULTS_RATING = 'Rating' const UI_DEFAULTS_RATING_ENABLE = 'Enable Rating Filter' const UI_DEFAULTS_TAGS = 'Tags' const UI_DEFAULTS_TAGS_ENABLE = 'Enable Default Tags' const UI_FAVOURITE_TAGS = 'Favourite Tags' const UI_DISLIKED_TAGS = 'Disliked Tags' const UI_VISITED_HIGHLIGHT = 'Highlight Visited' const UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES = 'Auto Next Page' class EHentaiSearchAndUITweaks extends BrazenBaseSearchEnhancer { constructor() { super({ isUserLoggedIn: false, itemDeepAnalysisSelector: '', itemLinkSelector: 'td.gl3m.glname > a, td.gl3c.glname > a, div.gl2e > div > a, a', itemListSelectors: 'table.itg, div.itg', itemNameSelector: 'td.gl3m.glname > a > div.glink, td.gl3c.glname > a > div.glink, div.gl4e.glname > div.glink, div.gl4t.glname.glink', itemSelectors: 'td.gl2e, div.gl1t', requestDelay: 0, scriptPrefix: 'e-hentai-ux-', tagSelectorGenerator: (tag) => { tag = tag.trim() if (IS_GALLERY_PAGE) { return 'div[id="td_' + tag.replace(' ', '_') + '"]' } return 'div.gt[title="' + tag + '"], div.gtl[title="' + tag + '"]' }, }) this._setupFeatures() this._setupUI() this._setupEvents() } /** * @param {string} tag * @return {string} * @private */ _formatTag(tag) { if (tag.includes(':') && !tag.includes('"') && (tag.includes(' ') || tag.includes('+'))) { tag = tag.replace(':', ':"') + '"' } return tag } /** * @param {{}} range * @param {URLSearchParams} queryParams * @private */ _handleDefaultPageRangeFilter(range, queryParams) { if (range.minimum > 0) { queryParams.set('f_spf', range.minimum) } if (range.maximum > 0) { queryParams.set('f_spf', range.maximum) } } /** * @param {string} rating * @param {URLSearchParams} queryParams * @private */ _handleDefaultRatingsFilter(rating, queryParams) { queryParams.set('f_srdd', rating) } /** * @param {string[]} tags * @param {URLSearchParams} queryParams * @private */ _handleDefaultTags(tags, queryParams) { let existingTags = queryParams.get('f_search') let updatedTags = existingTags let include = true for (let tag of tags) { if (!existingTags.includes(tag)) { updatedTags += '+' + this._formatTag(tag) } else { include = false break } } if (include) { queryParams.set('f_search', updatedTags) } } /** * @private */ _handleDefaults() { let queryParams = new URLSearchParams(window.location.search) let existingParams = queryParams.toString() if (!queryParams.has('next') && (this._getConfig(UI_DEFAULTS_PAGE_RANGE_ENABLE) || this._getConfig(UI_DEFAULTS_RATING_ENABLE) || this._getConfig(UI_DEFAULTS_TAGS_ENABLE))) { if (!queryParams.has('f_search')) { let existingTag = window.location.pathname.split('/').pop().trim() if (existingTag.length) { queryParams.set('f_search', this._formatTag(existingTag)) } } if (!queryParams.has('advsearch')) { queryParams.set('advsearch', '1') } let validatePageRange = (range, defaultValidator) => defaultValidator(range) && !queryParams.has('f_spf') && !queryParams.has('f_spt') this._performTogglableComplexOperation(UI_DEFAULTS_PAGE_RANGE_ENABLE, UI_DEFAULTS_PAGE_RANGE, validatePageRange, (range) => { this._handleDefaultPageRangeFilter(range, queryParams) }) let validateRatingFilter = (range, defaultValidator) => defaultValidator(range) && !queryParams.has('f_srdd') this._performTogglableComplexOperation(UI_DEFAULTS_RATING_ENABLE, UI_DEFAULTS_RATING, validateRatingFilter, (rating) => { this._handleDefaultRatingsFilter(rating, queryParams) }) this._performTogglableOperation(UI_DEFAULTS_TAGS_ENABLE, UI_DEFAULTS_TAGS, (tags) => { this._handleDefaultTags(tags, queryParams) }) let updatedParams = queryParams.toString().replaceAll('%2B', '+') if (updatedParams !== existingParams) { window.location = window.location.origin + '?' + updatedParams } } } /** * @private */ _setupEvents() { this._onValidateInit = () => !IS_SMALL_WINDOW this._onBeforeUIBuild.push(() => { this._performOperation(UI_VISITED_HIGHLIGHT, () => { GM_addStyle(`td.gl2e > div > a:visited > .glname > .glink {color: black;}`) }) if (IS_SEARCH_PAGE) { this._handleDefaults() } }) this._onAfterUIBuild.push(() => this._uiGen.getSelectedSection()[0].userScript = this) this._onItemHide = (item) => { if (item.is('td.gl2e')) { item.parent().addClass('noncompliant-item') item.parent().hide() } else { item.removeClass('noncompliant-item') item.hide() } } this._onItemShow = (item) => { if (item.is('td.gl2e')) { item.parent().removeClass('noncompliant-item') item.parent().show() } else { item.removeClass('noncompliant-item') item.show() } } } /** * @private */ _setupFeatures() { this._configurationManager .addFlagField(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES, 'Automatically navigates to the next page after opening all images.') .addFlagField(UI_VISITED_HIGHLIGHT, 'Colours the visited gallery links black, to make them distinct.') .addRangeField(UI_DEFAULTS_PAGE_RANGE, 0, 2000, 'Enable default page range filter in searches.') .addFlagField(UI_DEFAULTS_PAGE_RANGE_ENABLE, 'Always set these page limits in searches. Ignored if you set your own values on the page.') .addRadiosGroup(UI_DEFAULTS_RATING, [ ['2 stars', '2'], ['3 stars', '3'], ['4 stars', '4'], ['5 stars', '5'], ], 'Always set this rating filter in searches. Ignored if you set your own value on the page.') .addFlagField(UI_DEFAULTS_RATING_ENABLE, 'Enable default rating filter in searches') .addRulesetField(UI_DEFAULTS_TAGS, 5, 'Always add the following tags in search. Can be overridden with at least one tag present.') .addFlagField(UI_DEFAULTS_TAGS_ENABLE, 'Enable default tags in searches.') let otherTagSections = IS_GALLERY_PAGE ? $('#taglist') : null this._addItemTagHighlights(UI_FAVOURITE_TAGS, otherTagSections, 'favourite-tag', 'Specify favourite tags to highlight.', 10) this._addItemTagHighlights(UI_DISLIKED_TAGS, otherTagSections, 'disliked-tag', 'Specify disliked tags to highlight.', 10) this._addItemTagBlacklistFilter(20) } /** * @private */ _setupUI() { let openGalleryPages = [] if (IS_GALLERY_PAGE) { openGalleryPages = [ this._uiGen.createSeparator(), this._uiGen.createFormButton( 'Open Gallery Images', 'Opens all images on current page of this gallery.', () => { let images = $('div.gdtl a > img, div.gdtm a > img') let firstPage = images.first().attr('alt') let firstPageNumber = Number(firstPage) let paddedPageLength = firstPage.length let maxPages = firstPageNumber + images.length - 1 for (let page = maxPages; page >= firstPageNumber; page--) { let paddedPage = page.toString().padStart(paddedPageLength, '0') window.open(images.filter('[alt="' + paddedPage + '"]').parent().attr('href')) } if (this._getConfig(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES)) { let page = window.location.href.split('=')[1] || 0 let pageNavs = $('.ptt td') let maxPages = Number.parseInt(pageNavs.eq(pageNavs.length - 2).children('a').text()) - 1 if (page < maxPages) { let uri = window.location.href if (page === 0) { uri += '?p=1' } else { uri = uri.replace('?p=' + page++, '?p=' + page) } window.location = uri } } }), this._uiGen.createBreakSeparator(), this._configurationManager.createElement(UI_AUTO_NEXT_ON_OPEN_ALL_IMAGES), ] } this._userInterface = [ this._uiGen.createTabsSection(['Filters', 'Highlights', 'Defaults', 'Global'], [ this._uiGen.createTabPanel('Filters', true).append([ this._configurationManager.createElement(OPTION_ENABLE_TAG_BLACKLIST), this._configurationManager.createElement(FILTER_TAG_BLACKLIST), ]), this._uiGen.createTabPanel('Highlights').append([ this._configurationManager.createElement(UI_FAVOURITE_TAGS), this._configurationManager.createElement(UI_DISLIKED_TAGS), ]), this._uiGen.createTabPanel('Defaults').append([ this._configurationManager.createElement(UI_DEFAULTS_PAGE_RANGE_ENABLE), this._configurationManager.createElement(UI_DEFAULTS_PAGE_RANGE), this._uiGen.createSeparator(), this._configurationManager.createElement(UI_DEFAULTS_RATING), this._uiGen.createBreakSeparator(), this._configurationManager.createElement(UI_DEFAULTS_RATING_ENABLE), this._uiGen.createSeparator(), this._configurationManager.createElement(UI_DEFAULTS_TAGS_ENABLE), this._configurationManager.createElement(UI_DEFAULTS_TAGS), ]), this._uiGen.createTabPanel('Global').append([ this._configurationManager.createElement(UI_VISITED_HIGHLIGHT), this._configurationManager.createElement(OPTION_ALWAYS_SHOW_SETTINGS_PANE), this._uiGen.createSeparator(), this._createSettingsBackupRestoreFormActions(), ]), ]), this._uiGen.createStatisticsFormGroup(FILTER_TAG_BLACKLIST), ...openGalleryPages, this._uiGen.createSeparator(), this._createSettingsFormActions(), this._uiGen.createSeparator(), this._uiGen.createStatusSection(), ] } } (new EHentaiSearchAndUITweaks).init()