SankakuDLNamer

Help with DL naming

Ekde 2021/09/11. Vidu La ĝisdata versio.

// ==UserScript==
// @name        SankakuDLNamer
// @namespace   SankakuDLNamer
// @description Help with DL naming
// @author      SlimeySlither, sanchan
// @match       http*://chan.sankakucomplex.com/*
// @match       http*://idol.sankakucomplex.com/*
// @match       http*://beta.sankakucomplex.com/*
// @run-at      document-end
// @version     1.2.0
// @grant       GM_download
// ==/UserScript==

(function() {
	'use strict';

	const usePostId = false; // replaces hash with post ID if true
	const prefixPostId = false; // put post ID in front if true
	const debug = false;
	const maxEntries = 4;

	function main() {
		const tagSidebar = document.getElementById('tag-sidebar');
		if (tagSidebar == null) return;

		const tags = getSidebarTags(tagSidebar);
		if (debug) console.log(tags);

		const imageData = getImageData();
		if (debug) console.log(imageData);

		const postId = getPostId();
		if (debug) console.log(postId);

		const downloadName = generateFilename(tags, imageData, postId);
		if (debug) console.log(downloadName);

		const details = getDLDetails(imageData, downloadName);
		if (debug) console.log(details);

		addDownloadButton(tagSidebar, details);
	}

	function addDownloadButton(tagSidebar, details) {
		const imageLink = document.getElementById('highres');

		const a = document.createElement('a');
		a.href = '#';
		a.innerText = 'Download';
		a.onclick = function() { GM_download(details); return false; };

		const li = document.createElement('li');
		li.appendChild(a);

		// Add under 'Original' link under 'Details' section
		insertNodeAfter(li, imageLink.parentNode);
	}

	function insertNodeAfter(node, ref_node) {
		ref_node.parentNode.insertBefore(node, ref_node.nextSibling);
	}

	function getPostId() {
		const pathname = window.location.pathname;
		const temp = (pathname.endsWith('/') ? pathname.slice(0, -1) : pathname);
		return temp.substring(temp.lastIndexOf('/') + 1);
	}

	function cleanText(text) {
		// replace illegal filename characters https://stackoverflow.com/a/42210346
		return text.replaceAll(/[/\\?%*:|"<>]/g, '-');
	}

	function getSidebarTags(tagsidebar) {
		const cats = {}; // category -> [tags]
		for (const tagItem of tagsidebar.getElementsByTagName('li')) {
			let tag = '';

			// find tag
			for (const tagLink of tagItem.getElementsByTagName('a')) {
				if (tagLink.hasAttribute('id')) {
					tag = cleanText(tagLink.innerText);
					break;
				}
			}

			if (tag) {
				const cat = cleanText(tagItem.className);

				// insert tag in its category
				if (!(cat in cats)) {
					cats[cat] = [tag];
				} else {
					cats[cat].push(tag);
				}
			}
		}

		return cats;
	}

	function getImageData() {
		const imageLink = document.getElementById('highres');
		const url = new URL(imageLink.getAttribute('href'), document.baseURI);

		const filename = url.pathname.substring(url.pathname.lastIndexOf('/') + 1);

		const j = filename.lastIndexOf('.');
		const hash = filename.substring(0, j);
		const extension = filename.substring(j); // including '.'

		return { url, hash, extension };
	}

	function shortenTagList(tags) {
		if (tags.length > maxEntries) {
			tags = tags.slice(0, maxEntries);
			tags.push('...');
		}
		return tags;
	}

	function generateFilename(tags, imageData, postId) {
		let characters = tags['tag-type-character'];
		let copyrights = tags['tag-type-copyright'];
		let artists = tags['tag-type-artist'];

		// remove round brackets from character tags
		for (let i = 0; i < characters.length; i++) {
			let j = characters[i].indexOf('(');
			if (j > 0) {
				if ([' ', '_'].includes(characters[i][j - 1])) j--;
				characters[i] = characters[i].substring(0, j);
			}
		}

		// deduplicate
		characters = [...(new Set(characters))];

		characters.sort();
		copyrights.sort();
		artists.sort();

		characters = shortenTagList(characters);
		copyrights = shortenTagList(copyrights);
		artists = shortenTagList(artists);

		let tokens = [];

		if (usePostId && prefixPostId) {
			tokens.push(postId);
			tokens.push('-');
		}

		if (characters) tokens.push(characters.join(', '));
		if (copyrights) tokens.push('(' + copyrights.join(', ') + ')');
		if (artists) {
			tokens.push('drawn by');
			tokens.push(artists.join(', '));
		}

		if (!usePostId) {
			tokens.push(imageData.hash);
		} else if (!prefixPostId) {
			tokens.push(postId);
		}

		// remove '-' if there's nothing after it
		if (tokens[tokens.length - 1] === '-') {
			tokens = tokens.slice(0, -1);
		}

		const filename = tokens.join(' ');

		return filename + imageData.extension;
	}

	function getDLDetails(imageData, downloadName) {
		return {
			url: imageData.url.href,
			name: downloadName,
			saveAs: true,
		};
	}

	if (document.readyState === 'complete' || document.readyState === 'loaded' || document.readyState === 'interactive') {
		main();
	} else {
		document.addEventListener('DOMContentLoaded', main, false);
	}

})();