NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name TokkiPlugin_Kch // @grant GM_download // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @match *://kpop.re/*/* // @exclude-match *://kpop.re/all/* // @exclude-match *://kpop.re/admin/* // @version 1.3.2 // @author IUC // @license GPL-3.0-only // @updateURL https://openuserjs.org/meta/IUC/TokkiPlugin_Kch.meta.js // @description Adds certain features to kch. Look at options button to activate the features. // Changelog: // 1.3.2 // changed definition of args to make new openuserjs checker work // 1.3.1 // Added postID_files feature to add postID_ in front of downloaded filenames. (Can be activated and deactivated by toggling the option without site re-loading) // Adopted change to thumbnail feature. // ==/UserScript== /*jshint esversion: 6 */ (function(){ //From https://gitlab.com/loopvid/scripts/-/blob/master/userscripts/kpop.re_post_id_fix.user.js // version 1.1 // Feature: Highlights a post you select function fix_post_link(post) { var match, regex = /[#](\d+)/, link = post.querySelector( '.post-header a.post-id:not([data-id_fixed="true"])'); if (link) { match = regex.exec(link.href); if (match) { link.href = '#post'+match[1]; } link.dataset.id_fixed = 'true'; } } //------------------------------------------------ //anti-work mode //make all posts picture and webm only and hide no-media posts function toggle_anti_workmode(hidden) { if (hidden) { GM_addStyle('.post_whole_visibility { display: none }'); GM_addStyle('.post_body_visibility { display: none }'); } else { GM_addStyle('.post_whole_visibility { display: block }'); GM_addStyle('.post_body_visibility { display: block }'); } } // Adds custom css classes to posts for anti-workmode function add_post_invisible_class(post) { if (post.children[1].children.length < 2) { post.classList.add('post_whole_visibility'); } else if (post.children[1].children.length > 1) { if (post.children[1].children[0].children.length < 1) { post.classList.add('post_whole_visibility'); } else {post.children[1].children[1].classList.add('post_body_visibility'); } } } //------------------------------------------------ // Feature: Adds download buttons in posts to download all or a selection of pictures and videos in the post function download(links) { var amountOfFiles = links.length -1; if (amountOfFiles > 1) { let postNode = document.getElementById(links[0]); let checkCounter = amountOfFiles; for (let g = 1; g<amountOfFiles+1;g++){ let checkBoxValue = postNode.querySelector("#file" + g.toString()).checked; if (checkBoxValue) { var args = {}; if (postID_files){ args = { url: links[g], name: links[0].slice(links[0].lastIndexOf('post')+4,links[0].length) + '_' + links[g].slice(links[g].lastIndexOf("/")+1, links[g].length) }; } else { args = { url: links[g], name: links[g].slice(links[g].lastIndexOf("/")+1, links[g].length) }; } GM_download(args); } else { checkCounter--; } } if (checkCounter < 1) { for (let i = 1; i<links.length;i++) { var args_1 = {}; if (postID_files){ args_1 = { url: links[i], name: links[0].slice(links[0].lastIndexOf('post')+4,links[0].length) + '_' + links[i].slice(links[i].lastIndexOf("/")+1, links[i].length) }; } else { args_1= { url: links[i], name: links[i].slice(links[i].lastIndexOf("/")+1, links[i].length) }; } GM_download(args_1); } } } else { var args_2 = {}; if (postID_files){ args_2 = { url: links[1], name: links[0].slice(links[0].lastIndexOf('post')+4,links[0].length) + '_' + links[1].slice(links[1].lastIndexOf("/")+1, links[1].length) }; } else { args_2 = { url: links[1], name: links[1].slice(links[1].lastIndexOf("/")+1, links[1].length) }; } GM_download(args_2); } } function add_download_button(post) { let fileLinks = []; fileLinks[0] = post.getAttribute("id"); var fileIndex = 1; var section = post.children[1]; if (section.children.length > 1) { var footerPostControls = post.children[2].children[1]; var fileDiv = section.children[0]; var figures = fileDiv.children; for (let figure of figures) { var postFile = figure.children[1]; fileLinks[fileIndex] = postFile.getAttribute("href"); fileIndex++; } if (fileLinks.length>2){ // Adding checkboxes with label for (let c = 1; c<fileLinks.length;c++) { let boxContainer = document.createElement("a"); let fileCheckbox = document.createElement("input"); fileCheckbox.type = "checkbox"; fileCheckbox.id = "file"+ c.toString(); let fileCheckBoxLabel = document.createElement("label"); fileCheckBoxLabel.appendChild(document.createTextNode(c.toString())); fileCheckBoxLabel.style.marginRight = "3px"; boxContainer.appendChild(fileCheckBoxLabel); boxContainer.appendChild(fileCheckbox); boxContainer.classList.add("post-control"); boxContainer.style.marginRight = "5px"; footerPostControls.appendChild(boxContainer); } } // Adding download button with icon var downloadNode = document.createElement("a"); var downloadIcon = document.createElement("i"); downloadIcon.classList.add("fa", "fa-download"); downloadNode.appendChild(downloadIcon); downloadNode.setAttribute("id", "dlButton"); downloadNode.classList.add("post-control", "control"); downloadNode.style.marginLeft = "8px"; footerPostControls.appendChild(downloadNode); downloadNode.addEventListener('click', function(){ download(fileLinks); }); } } //--------------------------- // From https://gitlab.com/ysh16/dotfiles/-/blob/master/.config/qutebrowser/greasemonkey/kpop.re_thumbnail_files.user.js // version 0.4 // Feature: Shows Youtube link thumbnails as pictures in posts function show_thumbnail_for_link_as_picture(p) { let files = p.querySelector('.post-files'); if (!files) { files = document.createElement('div'); files.className = 'post-files'; p.querySelector('.post-body').insertAdjacentElement('afterbegin', files); } let embeds = p.querySelectorAll('.post-embed'); embeds.forEach(function(e) { let link = e.getAttribute('href'); let thumbnail = getThumbnail(link); let handled = false; p.querySelectorAll(".post-file-link").forEach(function(l) { if (l.attributes.href.value == link) handled = true; }); if (!thumbnail || handled) return; let figure = document.createElement('figure'); figure.className = 'post-file'; let caption = document.createElement('figcaption'); caption.className = 'post-file-info'; if (link.length > 30) caption.innerText = link.substr(0, 30) + '...'; else caption.innerText = link; figure.appendChild(caption); let a = document.createElement('a'); a.className = 'post-file-link'; a.href = link; a.target = '_blank'; figure.appendChild(a); let ico = document.createElement('i'); ico.className = 'fa fa-youtube-play post-file-badge post-file-video-badge'; a.appendChild(ico); let img = document.createElement('img'); img.className = 'post-file-thumb'; img.src = thumbnail; img.style.maxWidth = '200px'; img.style.maxHeight = '200px'; img.loading = 'lazy'; img.target = '_blank'; a.appendChild(img); p.querySelector('.post-files').insertAdjacentElement('beforeend', figure); let fileCount = files.querySelectorAll('.post-file').length; if (fileCount >= 1) p.classList.add('post_file'); if (fileCount > 1) p.classList.add('post_files'); }); } function getThumbnail(url) { let re = /^(https?:\/\/)?((www\.)?(youtube(-nocookie)?|youtube.googleapis)\.com.*(v\/|v=|vi=|vi\/|e\/|embed\/|user\/.*\/u\/\d+\/)|youtu\.be\/)([_0-9a-z-]+)/i; let match = url.match(re); let id = (match) ? match[7] : null; return (id) ? 'https://i.ytimg.com/vi/' + id + '/maxresdefault.jpg' : null; } //-------------------------------------- //Feature: (You) highlighter in posts function you_highlighter(post) { let post_body = post.getElementsByClassName('post-message'); for(var link of post_body[0].getElementsByTagName("a")){ if (link.innerHTML.includes("(You)")){ link.style.color = "rgb(252,152,16)"; link.style.fontWeight = "bold"; } } } //--------------------------------------- function init_config() { // Making sure there is always a valid config in local storage let config = GM_getValue('config', false); if (config == false){ config = {'download_buttons': false, 'link_thumbnails': false, 'post_selected_highlighter': false, 'you_highlighter': false, 'anti_workmode': false, 'postID_files': false}; GM_setValue('config', config); } return config; } // Returns a set of feature function objects that should be called according to config // Done here to avoid checking config for every post on first site load function check_config_for_features(config) { let features = new Set(); for (let key in config) { if (config[key]) { // download_buttons has to be executed before link_thumbnails to avoid making buttons for the fake pictures if (key == 'download_buttons') {features.add(add_download_button);} else if(key == 'link_thumbnails') {features.add(show_thumbnail_for_link_as_picture);} else if(key == 'post_selected_highlighter') {features.add(fix_post_link);} else if(key == 'you_highlighter') {features.add(you_highlighter);} } } return features; } // START SCRIPT // Load config let config = init_config(); let postID_files = config['postID_files']; // Tasks that are only done once after the site finished loading window.addEventListener('site_fully_loaded', function() { GM_addStyle('.post:target { border: 1px solid #555; }'); // replaces old setup_css() GM_addStyle('.post_body_visibility { }'); GM_addStyle('.post_whole_visibility { }'); toggle_anti_workmode(config['anti_workmode']); var features_to_execute = check_config_for_features(config); // Do nothing except prepare anti-workmode, if all features are disabled in config if(features_to_execute.size == 0) { [...document.getElementsByClassName("post")].forEach(post =>{ add_post_invisible_class(post); }); return;} // Loop over all posts for manipulations // document.getelementbyclassname runs in O(1) instead of selector which does O(n) [...document.getElementsByClassName("post")].forEach(post =>{ features_to_execute.forEach(func => {func(post);}); add_post_invisible_class(post); }); }, false); // Listener for new_post events. window.addEventListener("new_post_hook", function(event) { let new_post = event.detail.post; // Check config to only execute what is desired for the new post let features_to_execute = check_config_for_features(config); features_to_execute.forEach(func => {func(new_post);}); add_post_invisible_class(new_post); },false); //build config UI. Jesus Christ this takes way too many lines for something as simple as this... let settings_node = document.getElementsByClassName("modal-container"); let media_download_button_config = document.createElement("input"); media_download_button_config.type = "checkbox"; media_download_button_config.id = 'download_buttons_toggle'; media_download_button_config.name = 'download_buttons_toggle'; media_download_button_config.title = 'Toggles download buttons for pictures in posts'; media_download_button_config.classList.add("option-checkbox"); media_download_button_config.checked = config['download_buttons']; settings_node[0].children[2].children[1].children[0].appendChild(media_download_button_config); let media_download_button_config_label = document.createElement("label"); media_download_button_config_label.htmlFor = 'download_buttons_toggle'; media_download_button_config_label.classList.add('option-label'); media_download_button_config_label.textContent = "Post media download buttons"; media_download_button_config_label.title = 'Toggles download buttons for pictures in posts'; settings_node[0].children[2].children[1].children[0].appendChild(media_download_button_config_label); let break_element_1 = document.createElement("br"); settings_node[0].children[2].children[1].children[0].appendChild(break_element_1); //-- let link_thumbnail_config = document.createElement("input"); link_thumbnail_config.type = "checkbox"; link_thumbnail_config.id = 'link_thumbnail_toggle'; link_thumbnail_config.name = 'link_thumbnail_toggle'; link_thumbnail_config.title = 'Toggles showing link thumbnails as pictures'; link_thumbnail_config.classList.add("option-checkbox"); link_thumbnail_config.checked = config['link_thumbnails']; settings_node[0].children[2].children[1].children[0].appendChild(link_thumbnail_config); let link_thumbnail_config_label = document.createElement("label"); link_thumbnail_config_label.htmlFor = 'link_thumbnail_toggle'; link_thumbnail_config_label.classList.add('option-label'); link_thumbnail_config_label.textContent = "Link thumbnails"; link_thumbnail_config_label.title = 'Toggles showing link thumbnails as pictures'; settings_node[0].children[2].children[1].children[0].appendChild(link_thumbnail_config_label); let break_element_2 = document.createElement("br"); settings_node[0].children[2].children[1].children[0].appendChild(break_element_2); //-- let post_target_highlighter_config = document.createElement("input"); post_target_highlighter_config.type = "checkbox"; post_target_highlighter_config.id = 'post_target_highlighter_toggle'; post_target_highlighter_config.name = 'post_target_highlighter_toggle'; post_target_highlighter_config.title = 'Toggles border highlighting of a post you target'; post_target_highlighter_config.classList.add("option-checkbox"); post_target_highlighter_config.checked = config['post_selected_highlighter']; settings_node[0].children[2].children[1].children[0].appendChild(post_target_highlighter_config); let post_target_highlighter_config_label = document.createElement("label"); post_target_highlighter_config_label.htmlFor = 'post_target_highlighter_toggle'; post_target_highlighter_config_label.classList.add('option-label'); post_target_highlighter_config_label.textContent = "Post target highlighting"; post_target_highlighter_config_label.title = 'Toggles border highlighting of a post you target'; settings_node[0].children[2].children[1].children[0].appendChild(post_target_highlighter_config_label); let break_element_3 = document.createElement("br"); settings_node[0].children[2].children[1].children[0].appendChild(break_element_3); //-- let you_highlighter_config = document.createElement("input"); you_highlighter_config.type = "checkbox"; you_highlighter_config.id = 'you_highlighter_toggle'; you_highlighter_config.name = 'you_highlighter_toggle'; you_highlighter_config.title = 'Toggles highlighting (You)s'; you_highlighter_config.classList.add("option-checkbox"); you_highlighter_config.checked = config['you_highlighter']; settings_node[0].children[2].children[1].children[0].appendChild(you_highlighter_config); let you_highlighter_config_label = document.createElement("label"); you_highlighter_config_label.htmlFor = 'you_highlighter_toggle'; you_highlighter_config_label.classList.add('option-label'); you_highlighter_config_label.textContent = "(You) highlighter"; you_highlighter_config_label.title = 'Highlights (Yous)'; settings_node[0].children[2].children[1].children[0].appendChild(you_highlighter_config_label); let break_element_4 = document.createElement("br"); settings_node[0].children[2].children[1].children[0].appendChild(break_element_4); //-- let anti_workmode_config = document.createElement("input"); anti_workmode_config.type = "checkbox"; anti_workmode_config.id = 'anti_workmode_toggle'; anti_workmode_config.name = 'anti_workmode_toggle'; anti_workmode_config.title = 'Hides text in posts'; anti_workmode_config.classList.add("option-checkbox"); anti_workmode_config.checked = config['anti_workmode']; settings_node[0].children[2].children[1].children[0].appendChild(anti_workmode_config); let anti_workmode_config_label = document.createElement("label"); anti_workmode_config_label.htmlFor = 'anti_workmode_toggle'; anti_workmode_config_label.classList.add('option-label'); anti_workmode_config_label.textContent = "Anti-workmode"; anti_workmode_config_label.title = 'Hides text in posts'; settings_node[0].children[2].children[1].children[0].appendChild(anti_workmode_config_label); let break_element_5 = document.createElement("br"); settings_node[0].children[2].children[1].children[0].appendChild(break_element_5); //-- let postID_file_config = document.createElement("input"); postID_file_config.type = "checkbox"; postID_file_config.id = 'postID_file_toggle'; postID_file_config.name = 'postID_file_toggle'; postID_file_config.title = 'Adds postID in front of filenames'; postID_file_config.classList.add("option-checkbox"); postID_file_config.checked = config['postID_files']; settings_node[0].children[2].children[1].children[0].appendChild(postID_file_config); let postID_file_config_label = document.createElement("label"); postID_file_config_label.htmlFor = 'postID_file_toggle'; postID_file_config_label.classList.add('option-label'); postID_file_config_label.textContent = "Add PostID in filenames"; postID_file_config_label.title = 'Adds postID in front of filenames'; settings_node[0].children[2].children[1].children[0].appendChild(postID_file_config_label); // Add config changing functionality to all the config checkboxes media_download_button_config.onclick = function() { config['download_buttons'] = this.checked; GM_setValue('config', config); }; link_thumbnail_config.onclick = function() { config['link_thumbnails'] = this.checked; GM_setValue('config', config); }; post_target_highlighter_config.onclick = function() { config['post_selected_highlighter'] = this.checked; GM_setValue('config', config); }; you_highlighter_config.onclick = function() { config['you_highlighter'] = this.checked; GM_setValue('config', config); }; anti_workmode_config.onclick = function() { config['anti_workmode'] = this.checked; GM_setValue('config', config); toggle_anti_workmode(this.checked); }; postID_file_config.onclick = function() { config['postID_files'] = this.checked; GM_setValue('config', config); postID_files = this.checked; }; })();