NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Ehentai Uploader Smart Sort // @namespace https://github.com/Grinch27 // @version 0.1.6 // @description help Ehentai Uploader Sort uploade-Img Smarter! // @icon https://e-hentai.org/favicon.ico // @author Grinch27 // @match *://exhentai.org/upld/* // @match *://upld.e-hentai.org/* // @exclude https://exhentai.org/upld/manage // @exclude https://upld.e-hentai.org/manage // @grant none // @copyright 2022, Grinch27 (https://github.com/Grinch27) // @license GPL-3.0-or-later; https://www.gnu.org/licenses/gpl-3.0-standalone.html // @homepageURL https://github.com/Grinch27/EH-Uploader-Toolkit/blob/main/Ehentai%20Uploader%20Smart%20Sort.js // @updateURL https://openuserjs.org/meta/Grinch27/Ehentai_Uploader_Smart_Sort.meta.js // @downloadURL https://openuserjs.org/install/Grinch27/Ehentai_Uploader_Smart_Sort.user.js // @run-at document-end // ==/UserScript== /** * @author Grinch27 * @copyright Grinch27 * @license GNU General Public License v3.0 or later * * GNU General Public License * <https://www.gnu.org/licenses/>. */ (function () { 'use strict'; // class define class onclickJump_Button { constructor(innerHTML) { this.innerHTML = innerHTML; this.Button = document.createElement('button'); this.Button.innerHTML = innerHTML; this.Button.setAttribute("class", 'Tampermonkey'); } onclickJump(URL) { this.Button.setAttribute("href", URL); this.Button.setAttribute("onclick", `javascript:window.open('${URL}')`); this.Button.setAttribute("class", 'Tampermonkey-Jump'); } clickToCopy(str_copy) { this.Button.setAttribute('id', 'copy_btn'); this.Button.setAttribute("data-clipboard-text", str_copy); this.Button.setAttribute("class", 'Tampermonkey-Copy'); } append(Node) { Node.appendChild(this.Button); } } class EhentaiManageCell { constructor(cell_node) { this.cell_id_ = null; this.cell_href_ = null; this.span_id_ = null; this.span_value_ = null; this.img_id_ = null; this.img_alt_ = null; this.img_src_ = null; this.series_ = null; this.index_ = null; this.SetCellNode(cell_node); } SetCellNode(cell_node) { this.cell_id_ = cell_node.getAttribute('id'); this.SetSpanNode(cell_node.querySelector('input')); this.SetImgNode(cell_node.querySelector('img')); this.SetHrefNode(cell_node.querySelector('a[href]')); } SetSpanNode(span_node) { this.span_id_ = span_node.getAttribute('id'); this.span_value_ = Number(span_node.getAttribute('value')); } SetImgNode(img_node) { this.img_id_ = img_node.getAttribute('id'); this.img_alt_ = img_node.getAttribute('alt'); this.img_src_ = img_node.getAttribute('src'); this.MatchSeriesIndex(this.img_alt_.match(/\d+/g)); } MatchSeriesIndex(match_array) { if (match_array != null) { switch (match_array.length) { case 1: this.series_ = Number(match_array[0]); this.index_ = 0; break default: this.series_ = Number(match_array[0]); this.index_ = Number(match_array[1]); break } } } SetHrefNode(href_node) { if (href_node != null) { this.cell_href_ = href_node.getAttribute('href'); let temp_href = this.cell_href_.split('/').slice(-2)[0]; this.cell_href_ = this.cell_href_.replace(temp_href, temp_href.match(/.{10}/gi)[0]); temp_href = undefined; } else { this.cell_href_ = null; } } } function dynamicSort(property) { let sortOrder = 1; if (property[0] === '-') { sortOrder = -1; property = property.substr(1); } return function (a, b) { /* next line works with strings and numbers, * and you may want to customize it to your needs */ let result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; return result * sortOrder } } function dynamicSortMultiple() { /* refer: sort-array-of-objects-by-string-property-value * save the arguments object as it will be overwritten * note that arguments object is an array-like object * consisting of the names of the properties to sort by */ let props = arguments; return function (obj1, obj2) { let i = 0, result = 0; const numberOfProperties = props.length; /* try getting a different result from 0 (equal) * as long as we have extra properties to compare */ while (result === 0 && i < numberOfProperties) { result = dynamicSort(props[i])(obj1, obj2); i++; } return result } } function removeDuplicatesFromArrayOfObjects(target_array, property) { // refer: how-to-remove-all-duplicates-from-an-array-of-objects return target_array.filter((v, i, a) => a.findIndex(v2 => (v2[property] === v[property])) === i) // or .findLastIndex } function mergeArrayToLeft(left_array, right_array, property) { // refer: combine-json-arrays-by-key-javascript return left_array.map(x => Object.assign(x, right_array.find(y => y[property] == x[property]))); //merge to left } function countSeriesDuplicates(data_array) { let property = 'series_'; // refer: javascript-counting-duplicates-in-object-array-and-storing-the-count-as-a-new // refer: get-duplicates-in-array-of-strings-and-count-number-of-duplicates let res_count = Object.values( data_array.reduce( function (elem, { series_ }) { elem[series_] = elem[series_] || { series_, count: 0 }; elem[series_].count++; return elem }, Object.create(null) ) ); data_array = mergeArrayToLeft(data_array, res_count, property); // TODO: upgrade series_ and count(need_) to property(varialbe) return data_array } function scanCellInfo(cell_selector) { // collect img_cell to json_array let cell_node_array = document.querySelectorAll(cell_selector); let cell_json_array = []; for (let i = 0, cell_node; cell_node = cell_node_array[i]; i++) { cell_node = new EhentaiManageCell(cell_node); cell_json_array.push(JSON.parse(JSON.stringify(cell_node))) } cell_json_array = countSeriesDuplicates(cell_json_array) alert(`${cell_json_array.length} ImgCell Scanned`); // Data log for Scan debug let property = 'series_' let series_cell_array = removeDuplicatesFromArrayOfObjects(cell_json_array, property) console.log(series_cell_array); return cell_json_array } function sortPageselCell() { let cell_json_array = scanCellInfo('div[id^="cell"]'); // sort the json array cell_json_array.sort(dynamicSortMultiple("-series_", "index_")); // convert json_array to text ready for POST let post_text = 'do_reorder=manual'; for (let i = 0, each_param; each_param = cell_json_array[i]; i++) { post_text += `&${each_param.span_id_}=${i+1}`; } post_text += '&autosort='; return post_text } function postEhentaiManageSort(post_text) { if (document.URL.search(/(?<=(ulgid\=))\d+/gi) == -1) { alert("Not ulgid Page!\nAbort Post!"); } else { let ulgid_num = document.URL.match(/(?<=(ulgid\=))\d+/gi)[0]; let domain_org = document.URL.replace(/.*\/\//gi, '').replace(/managegallery.*/gi, ''); try { fetch(`https://${domain_org}managegallery?ulgid=${ulgid_num}`, { method: 'POST', headers: { 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 'Content-Type': 'application/x-www-form-urlencoded', //'queryString': JSON.stringify({'ulgid': ulgid_num}), //'Cookie': document.cookie, 'Cache-Control': 'max-age=0', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-User': '?1', 'Upgrade-Insecure-Requests': 1, }, body: JSON.parse(JSON.stringify(post_text)) }) alert("POST OK\nPlease Reflash"); } catch { alert("POST fail!"); } } } function userBoard(name_sortBoard) { //let name_sortBoard = 'SmartSort'; let user_flexbox = document.createElement('flexbox'); user_flexbox.setAttribute('class', `Tampermonkey-${name_sortBoard}`); user_flexbox.style = 'display: flex; flex-direction: row; justify-content: center; align-items: center;' document.querySelector('a[name="reorder"]').appendChild(user_flexbox) let style_EHbutton = "min-height: 26px; line-height: 20px; padding: 1px 5px 2px; border: 2px solid #8d8d8d; border-radius: 3px; opacity: 1.0;"; let id_ScanSmart = 'scan-smart'; let id_PostSmart = 'post-smart'; let button_sort = new onclickJump_Button("Scan Smart"); button_sort.Button.style = style_EHbutton; button_sort.Button.setAttribute("id", `${id_ScanSmart}`); button_sort.Button.onclick = function () { document.querySelector(`button[id="${id_ScanSmart}"]`).value = sortPageselCell(); }; button_sort.append(document.querySelector(`flexbox[class="Tampermonkey-${name_sortBoard}"]`)); let button_post = new onclickJump_Button("Post Smart"); button_post.Button.style = style_EHbutton; button_post.Button.setAttribute("id", `${id_PostSmart}`); button_post.Button.onclick = function () { let post_text = document.querySelector(`button[id="${id_ScanSmart}"]`).value; if (post_text.search(/autosort/gi) != -1) { postEhentaiManageSort(post_text); } else { alert("Scan Error!\nAbort Post!\nPlease check Scan Smart Button Value"); } } button_post.append(document.querySelector(`flexbox[class="Tampermonkey-${name_sortBoard}"]`)); } // run userBoard('SmartSort'); })();