https://soyak.party/ for the sharty

https://booru.soyak.party/ for the booru

User JS

From Soyjak Wiki, The Free Soycyclopedia
Jump to navigationJump to search

The theme and functionality of soyjak.party can be endlessly customized. This page catalogs working stylesheets and user scripts that soyjak.party users have created.

To add a CSS theme from here, on the soyjak.party website in the top right go to the Options->User CSS and paste it in the text box. To add javascript code snippets from here, copy and paste them into Options->User JS

Code Snippets

Sharty Fixes Gemerald

The original Sharty Fixes was deleted for an unknown reason. If you wish to use the original Sharty Fixes instead, it can be installed from here.

A small userscript that fixes the following bugs with the sharty:


  • Time inaccuracy Resolved
  • Google captcha not resetting Resolved
  • Quick reply Google captcha endless loading Resolved
  • Clicking post number sometimes refreshing the page
  • Multi-line automatic greentext
  • Reporting posts from the overboard
  • Automatically load and complete vichan text captcha (NOT KAPTCHA)
  • Reset text captcha when post fails
  • Submit post with Ctrl+Enter
  • Bypass wordfilter
  • Hide password
  • Hide threads from catalog (Shift+Click, triple tap on mobile)
  • Hide blotter
  • Search catalog
  • Image from URL (userscript manager only, User JS option breaks from CORS)
  • Remove kolyma jump datamining
  • (Optional) - Revert to classic UI
  • (Optional) - Quick quote, mass reply/quote
  • (Optional) - Anonymise name/trips
  • (Optional) - Truncate long posts
  • (Optional) - Hide images from saged posts


Install from Greasy Fork into a userscript manager.

Sharty Themes

Should be used with Sharty Fixes Gemerald

Install from Greasy Fork userscript manager.

SoyParty-X

Features:

  • Detects flood posts and hides them (you can set amount of lines and words to hide)
  • Forced anonymity (hides namefags, can be disabled)
  • Hides emailfags or sagefags (can be disabled for sagefags)
  • Highlights triple parentheses
  • Highlights datamining (makes posts glow)
  • Inline Youtube Previews (+invidious support)
  • Replaces "Gem" and "Coal" with minecraft icons
  • Replaces "Bump" and "Sage" with upvote and downvote icons

Expand to view the script

// ==UserScript==
// @name         SoyParty-X
// @namespace    datamining
// @version      0.2
// @description  Cure the cancer that is killing soyjak.party
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==

/* eslint-env jquery */

/*

Changelog:

0.2:

- hidePosts() now detects flood posts.

0.1:

- hidePosts()
- forcedAnonymity()
- highlightTripleParentheses()
- highlightDatamining()
- inlineYoutubePreviews()
- replaceCoalAndGemsWithIcon()
- replaceBumpAndSageWithIcons()

*/

(function SoyPartyX() {
  // true = hide posts where the e-mail is "sage".
  const _hideMailtoSage = true;

  // true = scrub email, trip, and force all names to be "Chud".
  // - Emailfags and tripfags are already hidden.
  // - Namefags aren't hidden, but turning this on will anonymize them.
  // false = don't change posts (default).
  const _enableForcedAnonymity = false;

  // Sets the limit for a post to be considered a flood post.
  // If one of the criteria is met, the post is hidden.
  const floodThresholdLines = 30;
  const floodThresholdCharacters = 3000;

  hidePosts();
  forcedAnonymity(); // Must come AFTER hidePosts()
  highlightTripleParentheses();
  highlightDatamining();
  inlineYoutubePreviews();
  replaceCoalAndGemsWithIcon();
  replaceBumpAndSageWithIcons();

  function hidePosts() {
    $(".post").each((i, el) => {
      const $el = $(el);
      const reasons = [];

      const isOp = $el.hasClass("op");

      if ($el.has(".trip").length) {
        reasons.push("tripfag");
      }
      if (_hideMailtoSage && $el.has('a.email[href^="mailto:sage"]').length) {
        reasons.push("sagefag");
      }
      if ($el.has('a.email:not([href^="mailto:sage"])').length) {
        reasons.push("emailfag");
      }

      const body = $el.has(".body");
      const bodyLines = body.html().split("<br>").length;
      const bodyLength = body.text().length;

      if (
        bodyLines > floodThresholdLines ||
        bodyLength > floodThresholdCharacters
      ) {
        reasons.push(
          `possible flooding: ${bodyLength} characters in ${bodyLines} lines`
        );
      }

      if (reasons.length) {
        const $notice = $("<div>")
          .addClass(`post ${isOp ? "op" : "reply"}`)
          .html(
            `<div class='body'><em>Post hidden (${reasons.join(
              ", "
            )}). Click to show.</em></div>`
          )
          .after($("<br>"));
        $notice.click(() => {
          $el.show();
          if (isOp) $el.prev(".files").show();
          $notice.hide();
        });
        $el.after($notice);
        $el.hide();
        if (isOp) $el.prev(".files").hide();
      }
    });
  }

  function forcedAnonymity() {
    if (!_enableForcedAnonymity) return;
    // Remove all emails.
    $("a.email").prop("outerHTML", "<span class='name'>Chud</span>");
    // Remove all tripcodes.
    $(".trip").prop("outerHTML", "");
    // Set all names to Chud.
    // Make sure not to overwrite (You)'s.
    $(".name")
      .filter((i, el) => !$(el).has(".own_post").length)
      .text("Chud");
  }

  function replaceWordWithIcon(re, icon) {
    const matchesRe = (index, post) => $(post).html().match(re);

    const template = (match) =>
      `<img src="${icon}" style="max-height:2em; vertical-align:middle">`;

    const applyTemplate = (index, post) => {
      const $post = $(post);
      const html = $post.html();
      $post.html(html.replace(re, template));
    };

    $("div.body").filter(matchesRe).each(applyTemplate);
  }

  function replaceCoalAndGemsWithIcon() {
    replaceWordWithIcon(/coal/gi, "https://i.imgur.com/O9iRcRv.png");
    replaceWordWithIcon(/gems?/gi, "https://i.imgur.com/BvjFdau.png");
  }

  function replaceBumpAndSageWithIcons() {
    // replaceWordWithIcon(/bump/gi, "https://i.imgur.com/zM2xOGh.png");
    // replaceWordWithIcon(/sage/gi, "https://i.imgur.com/2bsauzj.png");
    replaceWordWithIcon(/bump/gi, "https://i.imgur.com/Y7cpsW0.png");
    replaceWordWithIcon(/\bsage\b/gi, "https://i.imgur.com/ZarQtY3.png");
  }

  function highlightTripleParentheses() {
    const re = /\(\(\(.+?\)\)\)/g;
    const hasRe = (i, post) => post.innerHTML.match(re);

    const template = (match) =>
      `<span style='background-color:white;color:#0038B8;font-family:monospace;'>${match}</span>`;
    const applyTemplate = (i, post) => {
      post.innerHTML = post.innerHTML.replace(re, template);
    };

    $("div.body").filter(hasRe).each(applyTemplate);
  }

  function highlightDatamining() {
    const reGlowie =
      /data(\s*|-)min(ing|er|ed)|(sell|selling|sold)\s+(my|our)?\s+data|cuckflare|cloudflare|cloud fleur/i;
    const hasReGlowie = (i, post) => post.innerHTML.match(reGlowie);
    const applyTemplate = (i, post) =>
      $(post).css({
        backgroundColor: "#D7EFD7",
        boxShadow: "#66FF66 0 0 2rem 0",
      });
    $(".reply").filter(hasReGlowie).each(applyTemplate);
  }

  function inlineYoutubePreviews() {
    const re = /(?:youtu\.be\/|\/watch\?v=)(.{11})/;
    const previewTemplate = (videoId) =>
      `<a href="https://youtube.com/watch?v=${videoId}">https://youtube.com/watch?v=${videoId}</a><br><img style="max-width:255px;max-height:255px" src="https://i.ytimg.com/vi/${videoId}/hqdefault.jpg" /><br><em>Watch on <a href="https://yewtu.be/${videoId}">Invidious</a> (less datamining)</em><br>`;
    $(".body a")
      .filter(function (i) {
        return $(this).prop("href").match(re);
      })
      .each(function (i) {
        $(this).prop("outerHTML", previewTemplate(this.href.match(re)[1]));
      });
  }
})();

Post Filters

Allows you to filter posts based on comments, subject, name, and tripcode To access filters click on options button.

Expand to view the script

// @name         Post Filters for soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Filter posts on soyjak.party
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
/*
 * post-menu.js - adds dropdown menu to posts
 *
 * Creates a global Menu object with four public methods:
 *
 *   Menu.onclick(fnc)
 *     registers a function to be executed after button click, before the menu is displayed
 *   Menu.add_item(id, text[, title])
 *     adds an item to the top level of menu
 *   Menu.add_submenu(id, text)
 *     creates and returns a List object through which to manipulate the content of the submenu
 *   Menu.get_submenu(id)
 *     returns the submenu with the specified id from the top level menu
 *
 *   The List object contains all the methods from Menu except onclick()
 *
 *   Example usage:
 *     Menu.add_item('filter-menu-hide', 'Hide post');
 *     Menu.add_item('filter-menu-unhide', 'Unhide post');
 *
 *     submenu = Menu.add_submenu('filter-menu-add', 'Add filter');
 *         submenu.add_item('filter-add-post-plus', 'Post +', 'Hide post and all replies');
 *         submenu.add_item('filter-add-id', 'ID');
 *  
 * Usage:
 *   $config['additional_javascript'][] = 'js/jquery.min.js';
 *   $config['additional_javascript'][] = 'js/post-menu.js';
 */
$(document).ready(function () {

var List = function (menuId, text) {
	this.id = menuId;
	this.text = text;
	this.items = [];

	this.add_item = function (itemId, text, title) {
		this.items.push(new Item(itemId, text, title));
	};
	this.list_items = function () {
		var array = [];
		var i, length, obj, $ele;

		if ($.isEmptyObject(this.items))
			return;

		length = this.items.length;
		for (i = 0; i < length; i++) {
			obj = this.items[i];

			$ele = $('<li>', {id: obj.id}).text(obj.text);
			if ('title' in obj) $ele.attr('title', obj.title);

			if (obj instanceof Item) {
				$ele.addClass('post-item');
			} else {
				$ele.addClass('post-submenu');

				$ele.prepend(obj.list_items());
				$ele.append($('<span>', {class: 'post-menu-arrow'}).text('»'));
			}

			array.push($ele);
		}

		return $('<ul>').append(array);
	};
	this.add_submenu = function (menuId, text) {
		var ele = new List(menuId, text);
		this.items.push(ele);
		return ele;
	};
	this.get_submenu = function (menuId) {
		for (var i = 0; i < this.items.length; i++) {
			if ((this.items[i] instanceof Item) || this.items[i].id != menuId) continue;
			return this.items[i];
		}
	};
};

var Item = function (itemId, text, title) {
	this.id = itemId;
	this.text = text;

	// optional
	if (typeof title != 'undefined') this.title = title;
};

function buildMenu(e) {
	var pos = $(e.target).offset();
	var i, length;

	var $menu = $('<div class="post-menu"></div>').append(mainMenu.list_items());

	//  execute registered click handlers
	length = onclick_callbacks.length;
	for (i = 0; i < length; i++) {
		onclick_callbacks[i](e, $menu);
	}

	//  set menu position and append to page
	 $menu.css({top: pos.top, left: pos.left + 20});
	 $('body').append($menu);
}

function addButton(post) {
	var $ele = $(post);
	$ele.find('input.delete').after(
		$('<a>', {href: '#', class: 'post-btn', title: 'Post menu'}).text('▶')
	);
}


/* * * * * * * * * *
    Public methods
 * * * * * * * * * */
var Menu = {};
var mainMenu = new List();
var onclick_callbacks = [];

Menu.onclick = function (fnc) {
	onclick_callbacks.push(fnc);
};

Menu.add_item = function (itemId, text, title) {
	mainMenu.add_item(itemId, text, title);
};

Menu.add_submenu = function (menuId, text) {
	return mainMenu.add_submenu(menuId, text);
};

Menu.get_submenu = function (id) {
	return mainMenu.get_submenu(id);
};

window.Menu = Menu;


/* * * * * * * *
    Initialize
 * * * * * * * */

/*  Styling
 */
var $ele, cssStyle, cssString;

$ele = $('<div>').addClass('post reply').hide().appendTo('body');
cssStyle = $ele.css(['border-top-color']);
cssStyle.hoverBg = $('body').css('background-color');
$ele.remove();

cssString =
	'\n/*** Generated by post-menu ***/\n' +
	'.post-menu {position: absolute; font-size: 12px; line-height: 1.3em;}\n' +
	'.post-menu ul {\n' +
	'    background-color: '+ cssStyle['border-top-color'] +'; border: 1px solid #666;\n' +
	'    list-style: none; padding: 0; margin: 0; white-space: nowrap;\n}\n' +
	'.post-menu .post-submenu{white-space: normal; width: 90px;}' +
	'.post-menu .post-submenu>ul{white-space: nowrap; width: auto;}' +
	'.post-menu li {cursor: pointer; position: relative; padding: 4px 4px; vertical-align: middle;}\n' +
	'.post-menu li:hover {background-color: '+ cssStyle.hoverBg +';}\n' +
	'.post-menu ul ul {display: none; position: absolute;}\n' +
	'.post-menu li:hover>ul {display: block; left: 100%; margin-top: -3px;}\n' +
	'.post-menu-arrow {float: right; margin-left: 10px;}\n' +
	'.post-menu.hidden, .post-menu .hidden {display: none;}\n' +
	'.post-btn {transition: transform 0.1s; width: 15px; text-align: center; font-size: 10pt; opacity: 0.8; text-decoration: none; margin: -6px 0px 0px -5px !important; display: inline-block;}\n' +
	'.post-btn:hover {opacity: 1;}\n' +
	'.post-btn-open {transform: rotate(90deg);}\n';

if (!$('style.generated-css').length) $('<style class="generated-css">').appendTo('head');
$('style.generated-css').html($('style.generated-css').html() + cssString);

/*  Add buttons
 */
$('.reply:not(.hidden), .thread>.op').each(function () {
	addButton(this);
 });

 /*  event handlers
  */
$('form[name=postcontrols]').on('click', '.post-btn', function (e) {
	e.preventDefault();
	var post = e.target.parentElement.parentElement;
	$('.post-menu').remove();

	if ($(e.target).hasClass('post-btn-open')) {
		$('.post-btn-open').removeClass('post-btn-open');
	} else {
		//  close previous button
		$('.post-btn-open').removeClass('post-btn-open');
		$(post).find('.post-btn').addClass('post-btn-open');

		buildMenu(e);
	}
});

$(document).on('click', function (e){
	if ($(e.target).hasClass('post-btn') || $(e.target).hasClass('post-submenu'))
		return;

	$('.post-menu').remove();
	$('.post-btn-open').removeClass('post-btn-open');
});

// on new posts
$(document).on('new_post', function (e, post) {
	addButton(post);
});

$(document).trigger('menu_ready');
});


// Post Filters
if (active_page === 'thread' || active_page === 'index' || active_page === 'catalog' || active_page === 'ukko') {
	$(document).on('menu_ready', function () {
		'use strict';
		
		// returns blacklist object from storage
		function getList() {
			return JSON.parse(localStorage.postFilter);
		}

		// stores blacklist into storage and reruns the filter
		function setList(blacklist) {
			localStorage.postFilter = JSON.stringify(blacklist);
			$(document).trigger('filter_page');
		}

		// unit: seconds
		function timestamp() {
			return Math.floor((new Date()).getTime() / 1000);
		}

		function initList(list, boardId, threadId) {
			if (typeof list.postFilter[boardId] == 'undefined') {
				list.postFilter[boardId] = {};
				list.nextPurge[boardId] = {};
			}
			if (typeof list.postFilter[boardId][threadId] == 'undefined') {
				list.postFilter[boardId][threadId] = [];
			}
			list.nextPurge[boardId][threadId] = {timestamp: timestamp(), interval: 86400};  // 86400 seconds == 1 day
		}

		function addFilter(type, value, useRegex) {
			var list = getList();
			var filter = list.generalFilter;
			var obj = {
				type: type,
				value: value,
				regex: useRegex
			};

			for (var i=0; i<filter.length; i++) {
				if (filter[i].type == type && filter[i].value == value && filter[i].regex == useRegex)
					return;
			}

			filter.push(obj);
			setList(list);
			drawFilterList();
		}

		function removeFilter(type, value, useRegex) {
			var list = getList();
			var filter = list.generalFilter;

			for (var i=0; i<filter.length; i++) {
				if (filter[i].type == type && filter[i].value == value && filter[i].regex == useRegex) {
					filter.splice(i, 1);
					break;
				}
			}

			setList(list);
			drawFilterList();
		}

		function nameSpanToString(el) {
			var s = ''; 

			$.each($(el).contents(), function(k,v) {
				if (v.nodeName === 'IMG')
					s=s+$(v).attr('alt')
				
				if (v.nodeName === '#text')
					s=s+v.nodeValue
			});
			return s.trim();
		}

		var blacklist = {
			add: {
				post: function (boardId, threadId, postId, hideReplies) {
					var list = getList();
					var filter = list.postFilter;

					initList(list, boardId, threadId);

					for (var i in filter[boardId][threadId]) {
						if (filter[boardId][threadId][i].post == postId) return;
					}
					filter[boardId][threadId].push({
						post: postId,
						hideReplies: hideReplies
					});
					setList(list);
				},
				uid: function (boardId, threadId, uniqueId, hideReplies) {
					var list = getList();
					var filter = list.postFilter;

					initList(list, boardId, threadId);

					for (var i in filter[boardId][threadId]) {
						if (filter[boardId][threadId][i].uid == uniqueId) return;
					}
					filter[boardId][threadId].push({
						uid: uniqueId,
						hideReplies: hideReplies
					});
					setList(list);
				}
			},
			remove: {
				post: function (boardId, threadId, postId) {
					var list = getList();
					var filter = list.postFilter;

					// thread already pruned
					if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
						return;

					for (var i=0; i<filter[boardId][threadId].length; i++) {
						if (filter[boardId][threadId][i].post == postId) {
							filter[boardId][threadId].splice(i, 1);
							break;
						}
					}

					if ($.isEmptyObject(filter[boardId][threadId])) {
						delete filter[boardId][threadId];
						delete list.nextPurge[boardId][threadId];

						if ($.isEmptyObject(filter[boardId])) {
							delete filter[boardId];
							delete list.nextPurge[boardId];
						}
					}
					setList(list);
				},
				uid: function (boardId, threadId, uniqueId) {
					var list = getList();
					var filter = list.postFilter;

					// thread already pruned
					if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
						return;

					for (var i=0; i<filter[boardId][threadId].length; i++) {
						if (filter[boardId][threadId][i].uid == uniqueId) {
							filter[boardId][threadId].splice(i, 1);
							break;
						}
					}

					if ($.isEmptyObject(filter[boardId][threadId])) {
						delete filter[boardId][threadId];
						delete list.nextPurge[boardId][threadId];

						if ($.isEmptyObject(filter[boardId])) {
							delete filter[boardId];
							delete list.nextPurge[boardId];
						}
					}
					setList(list);
				}
			}
		};

		/* 
		 *  hide/show the specified thread/post
		 */
		function hide(ele) {
			var $ele = $(ele);

			if ($(ele).data('hidden'))
				return;

			$(ele).data('hidden', true);
			if ($ele.hasClass('op')) {
				$ele.parent().find('.body, .files, .video-container').not($ele.children('.reply').children()).hide();

				// hide thread replies on index view
				if (active_page == 'index' || active_page == 'ukko') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').hide();
			} else {
				// normal posts
				$ele.children('.body, .files, .video-container').hide();
			}
		}
		function show(ele) {
			var $ele = $(ele);

			$(ele).data('hidden', false);
			if ($ele.hasClass('op')) {
				$ele.parent().find('.body, .files, .video-container').show();
				if (active_page == 'index') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').show();
			} else {
				// normal posts
				$ele.children('.body, .files, .video-container').show();
			}
		}

		/* 
		 *  create filter menu when the button is clicked
		 */
		function initPostMenu(pageData) {
			var Menu = window.Menu;
			var submenu;
			Menu.add_item('filter-menu-hide', _('Hide post'));
			Menu.add_item('filter-menu-unhide', _('Unhide post'));

			submenu = Menu.add_submenu('filter-menu-add', _('Add filter'));
				submenu.add_item('filter-add-post-plus', _('Post +'), _('Hide post and all replies'));
				submenu.add_item('filter-add-id', _('ID'));
				submenu.add_item('filter-add-id-plus', _('ID +'), _('Hide ID and all replies'));
				submenu.add_item('filter-add-name', _('Name'));
				submenu.add_item('filter-add-trip', _('Tripcode'));

			submenu = Menu.add_submenu('filter-menu-remove', _('Remove filter'));
				submenu.add_item('filter-remove-id', _('ID'));
				submenu.add_item('filter-remove-name', _('Name'));
				submenu.add_item('filter-remove-trip', _('Tripcode'));

			Menu.onclick(function (e, $buffer) {
				var ele = e.target.parentElement.parentElement;
				var $ele = $(ele);

				var threadId = $ele.parent().attr('id').replace('thread_', '');
				var boardId = $ele.parent().data('board');
				var postId = $ele.find('.post_no').not('[id]').text();
				if (pageData.hasUID) {
					var postUid = $ele.find('.poster_id').text();
				}

				var postName;
				var postTrip = '';
				if (!pageData.forcedAnon) {
					postName = (typeof $ele.find('.name').contents()[0] == 'undefined') ? '' : nameSpanToString($ele.find('.name')[0]);
					postTrip = $ele.find('.trip').text();
				}

				/*  display logic and bind click handlers
				 */

				 // unhide button
				if ($ele.data('hidden')) {
					$buffer.find('#filter-menu-unhide').click(function () {
						//  if hidden due to post id, remove it from blacklist
						//  otherwise just show this post
						blacklist.remove.post(boardId, threadId, postId);
						show(ele);
					});
					$buffer.find('#filter-menu-hide').addClass('hidden');
				} else {
					$buffer.find('#filter-menu-unhide').addClass('hidden');
					$buffer.find('#filter-menu-hide').click(function () {
						blacklist.add.post(boardId, threadId, postId, false);
					});
				}

				//  post id
				if (!$ele.data('hiddenByPost')) {
					$buffer.find('#filter-add-post-plus').click(function () {
						blacklist.add.post(boardId, threadId, postId, true);
					});
				} else {
					$buffer.find('#filter-add-post-plus').addClass('hidden');
				}

				// UID
				if (pageData.hasUID && !$ele.data('hiddenByUid')) {
					$buffer.find('#filter-add-id').click(function () {
						blacklist.add.uid(boardId, threadId, postUid, false);
					});
					$buffer.find('#filter-add-id-plus').click(function () {
						blacklist.add.uid(boardId, threadId, postUid, true);
					});

					$buffer.find('#filter-remove-id').addClass('hidden');
				} else if (pageData.hasUID) {
					$buffer.find('#filter-remove-id').click(function () {
						blacklist.remove.uid(boardId, threadId, postUid);
					});

					$buffer.find('#filter-add-id').addClass('hidden');
					$buffer.find('#filter-add-id-plus').addClass('hidden');
				} else {
					// board doesn't use UID
					$buffer.find('#filter-add-id').addClass('hidden');
					$buffer.find('#filter-add-id-plus').addClass('hidden');
					$buffer.find('#filter-remove-id').addClass('hidden');
				}

				//  name
				if (!pageData.forcedAnon && !$ele.data('hiddenByName')) {
					$buffer.find('#filter-add-name').click(function () {
						addFilter('name', postName, false);
					});

					$buffer.find('#filter-remove-name').addClass('hidden');
				} else if (!pageData.forcedAnon) {
					$buffer.find('#filter-remove-name').click(function () {
						removeFilter('name', postName, false);
					});

					$buffer.find('#filter-add-name').addClass('hidden');
				} else {
					// board has forced anon
					$buffer.find('#filter-remove-name').addClass('hidden');
					$buffer.find('#filter-add-name').addClass('hidden');
				}

				//  tripcode
				if (!pageData.forcedAnon && !$ele.data('hiddenByTrip') && postTrip !== '') {
					$buffer.find('#filter-add-trip').click(function () {
						addFilter('trip', postTrip, false);
					});

					$buffer.find('#filter-remove-trip').addClass('hidden');
				} else if (!pageData.forcedAnon && postTrip !== '') {
					$buffer.find('#filter-remove-trip').click(function () {
						removeFilter('trip', postTrip, false);
					});

					$buffer.find('#filter-add-trip').addClass('hidden');
				} else {
					// board has forced anon
					$buffer.find('#filter-remove-trip').addClass('hidden');
					$buffer.find('#filter-add-trip').addClass('hidden');
				}

				/*  hide sub menus if all items are hidden
				 */
				if (!$buffer.find('#filter-menu-remove > ul').children().not('.hidden').length) {
					$buffer.find('#filter-menu-remove').addClass('hidden');
				}
				if (!$buffer.find('#filter-menu-add > ul').children().not('.hidden').length) {
					$buffer.find('#filter-menu-add').addClass('hidden');
				}
			});
		}

		/* 
		 *  hide/unhide thread on index view
		 */
		function quickToggle(ele, threadId, pageData) {
			/*if ($(ele).find('.hide-thread-link').length)
				$('.hide-thread-link').remove();*/

			if ($(ele).hasClass('op') && !$(ele).find('.hide-thread-link').length) {
				$('<a class="hide-thread-link" style="float:left;margin-right:5px" href="javascript:void(0)">[' + ($(ele).data('hidden') ? '+' : '–') + ']</a>')
					.insertBefore($(ele).find(':not(h2,h2 *):first'))
					.click(function() {
						var postId = $(ele).find('.post_no').not('[id]').text();
						var hidden = $(ele).data('hidden');
						var boardId = $(ele).parents('.thread').data('board');
					
						if (hidden) {
							blacklist.remove.post(boardId, threadId, postId, false);
							$(this).html('[–]');
						} else {
							blacklist.add.post(boardId, threadId, postId, false);
							$(this).text('[+]');
						}
					});
			}
		}

		/*
		 *  determine whether the reply post should be hidden
		 *   - applies to all posts on page load or filtering rule change
		 *   - apply to new posts on thread updates
		 *   - must explicitly set the state of each attributes because filter will reapply to all posts after filtering rule change
		 */
		function filter(post, threadId, pageData) {
			var $post = $(post);

			var list = getList();
			var postId = $post.find('.post_no').not('[id]').text();
			var name, trip, uid, subject, comment;
			var i, length, array, rule, pattern;  // temp variables

			var boardId	      = $post.data('board');
			if (!boardId) boardId = $post.parents('.thread').data('board');

			var localList   = pageData.localList;
			var noReplyList = pageData.noReplyList;
			var hasUID      = pageData.hasUID;
			var forcedAnon  = pageData.forcedAnon;

			var hasTrip = ($post.find('.trip').length > 0);
			var hasSub = ($post.find('.subject').length > 0);

			$post.data('hidden', false);
			$post.data('hiddenByUid', false);
			$post.data('hiddenByPost', false);
			$post.data('hiddenByName', false);
			$post.data('hiddenByTrip', false);
			$post.data('hiddenBySubject', false);
			$post.data('hiddenByComment', false);

			// add post with matched UID to localList
			if (hasUID &&
				typeof list.postFilter[boardId] != 'undefined' &&
				typeof list.postFilter[boardId][threadId] != 'undefined') {
				uid = $post.find('.poster_id').text();
				array = list.postFilter[boardId][threadId];

				for (i=0; i<array.length; i++) {
					if (array[i].uid == uid) {
						$post.data('hiddenByUid', true);
						localList.push(postId);
						if (array[i].hideReplies) noReplyList.push(postId);
						break;
					}
				}
			}

			// match localList
			if (localList.length) {
				if ($.inArray(postId, localList) != -1) {
					if ($post.data('hiddenByUid') !== true) $post.data('hiddenByPost', true);
					hide(post);
				}
			}

			// matches generalFilter
			if (!forcedAnon)
				name = (typeof $post.find('.name').contents()[0] == 'undefined') ? '' : nameSpanToString($post.find('.name')[0]);
			if (!forcedAnon && hasTrip)
				trip = $post.find('.trip').text();
			if (hasSub)
				subject = $post.find('.subject').text();

			array = $post.find('.body').contents().filter(function () {if ($(this).text() !== '') return true;}).toArray();
			array = $.map(array, function (ele) {
				return $(ele).text().trim();
			});
			comment = array.join(' ');


			for (i = 0, length = list.generalFilter.length; i < length; i++) {
				rule = list.generalFilter[i];

				if (rule.regex) {
					pattern = new RegExp(rule.value);
					switch (rule.type) {
						case 'name':
							if (!forcedAnon && pattern.test(name)) {
								$post.data('hiddenByName', true);
								hide(post);
							}
							break;
						case 'trip':
							if (!forcedAnon && hasTrip && pattern.test(trip)) {
								$post.data('hiddenByTrip', true);
								hide(post);
							}
							break;
						case 'sub':
							if (hasSub && pattern.test(subject)) {
								$post.data('hiddenBySubject', true);
								hide(post);
							}
							break;
						case 'com':
							if (pattern.test(comment)) {
								$post.data('hiddenByComment', true);
								hide(post);
							}
							break;
					}
				} else {
					switch (rule.type) {
						case 'name':
							if (!forcedAnon && rule.value == name) {
								$post.data('hiddenByName', true);
								hide(post);
							}
							break;
						case 'trip':
							if (!forcedAnon && hasTrip && rule.value == trip) {
								$post.data('hiddenByTrip', true);
								hide(post);
							}
							break;
						case 'sub':
							pattern = new RegExp('\\b'+ rule.value+ '\\b');
							if (hasSub && pattern.test(subject)) {
								$post.data('hiddenBySubject', true);
								hide(post);
							}
							break;
						case 'com':
							pattern = new RegExp('\\b'+ rule.value+ '\\b');
							if (pattern.test(comment)) {
								$post.data('hiddenByComment', true);
								hide(post);
							}
							break;
					}
				}
			}

			// check for link to filtered posts
			$post.find('.body a').not('[rel="nofollow"]').each(function () {
				var replyId = $(this).text().match(/^>>(\d+)$/);

				if (!replyId)
					return;

				replyId = replyId[1];
				if ($.inArray(replyId, noReplyList) != -1) {
					hide(post);
				}
			});

			// post didn't match any filters
			if (!$post.data('hidden')) {
				show(post);
			}
		}

		/*  (re)runs the filter on the entire page
		 */
		 function filterPage(pageData) {
			var list = getList();

			if (active_page != 'catalog') {

				// empty the local and no-reply list
				pageData.localList = [];
				pageData.noReplyList = [];

				$('.thread').each(function () {
					var $thread = $(this);
					// disregard the hidden threads constructed by post-hover.js
					if ($thread.css('display') == 'none')
						return;

					var threadId = $thread.attr('id').replace('thread_', '');
					var boardId = $thread.data('board');
					var op = $thread.children('.op')[0];
					var i, array;  // temp variables

					// add posts to localList and noReplyList
					if (typeof list.postFilter[boardId] != 'undefined' && typeof list.postFilter[boardId][threadId] != 'undefined') {
						array = list.postFilter[boardId][threadId];
						for (i=0; i<array.length; i++) {
							if ( typeof array[i].post == 'undefined')
								continue;

							pageData.localList.push(array[i].post);
							if (array[i].hideReplies) pageData.noReplyList.push(array[i].post);
						}
					}
					// run filter on OP
					filter(op, threadId, pageData);
					quickToggle(op, threadId, pageData);

					// iterate filter over each post
					if (!$(op).data('hidden') || active_page == 'thread') {
						$thread.find('.reply').not('.hidden').each(function () {
							filter(this, threadId, pageData);
						});
					}

				});
			} else {
				var postFilter = list.postFilter[pageData.boardId];
				var $collection = $('.mix');

				if ($.isEmptyObject(postFilter))
					return;

				// for each thread that has filtering rules
				// check if filter contains thread OP and remove the thread from catalog
				$.each(postFilter, function (key, thread) {
					var threadId = key;
					$.each(thread, function () {
						if (this.post == threadId) {
							$collection.filter('[data-id='+ threadId +']').remove();
						}
					});
				});
			}
		 }

		function initStyle() {
			var $ele, cssStyle, cssString;

			$ele = $('<div>').addClass('post reply').hide().appendTo('body');
			cssStyle = $ele.css(['background-color', 'border-color']);
			cssStyle.hoverBg = $('body').css('background-color');
			$ele.remove();

			cssString = '\n/*** Generated by post-filter ***/\n' +
				'#filter-control input[type=text] {width: 130px;}' +
				'#filter-control input[type=checkbox] {vertical-align: middle;}' +
				'#filter-control #clear {float: right;}\n' +
				'#filter-container {margin-top: 20px; border: 1px solid; height: 270px; overflow: auto;}\n' +
				'#filter-list {width: 100%; border-collapse: collapse;}\n' +
				'#filter-list th {text-align: center; height: 20px; font-size: 14px; border-bottom: 1px solid;}\n' +
				'#filter-list th:nth-child(1) {text-align: center; width: 70px;}\n' +
				'#filter-list th:nth-child(2) {text-align: left;}\n' +
				'#filter-list th:nth-child(3) {text-align: center; width: 58px;}\n' +
				'#filter-list tr:not(#header) {height: 22px;}\n' +
				'#filter-list tr:nth-child(even) {background-color:rgba(255, 255, 255, 0.5);}\n' +
				'#filter-list td:nth-child(1) {text-align: center; width: 70px;}\n' +
				'#filter-list td:nth-child(3) {text-align: center; width: 58px;}\n' +
				'#confirm {text-align: right; margin-bottom: -18px; padding-top: 2px; font-size: 14px; color: #FF0000;}';

			if (!$('style.generated-css').length) $('<style class="generated-css">').appendTo('head');
			$('style.generated-css').html($('style.generated-css').html() + cssString);
		}

		function drawFilterList() {
			var list = getList().generalFilter;
			var $ele = $('#filter-list');
			var $row, i, length, obj, val;

			var typeName = {
				name: 'name',
				trip: 'tripcode',
				sub: 'subject',
				com: 'comment'
			};

			$ele.empty();

			$ele.append('<tr id="header"><th>Type</th><th>Content</th><th>Remove</th></tr>');
			for (i = 0, length = list.length; i < length; i++) {
				obj = list[i];

				// display formatting
				val = (obj.regex) ? '/'+ obj.value +'/' : obj.value;

				$row = $('<tr>');
				$row.append(
					'<td>'+ typeName[obj.type] +'</td>',
					'<td>'+ val +'</td>',
					$('<td>').append(
						$('<a>').html('X')
							.addClass('del-btn')
							.attr('href', '#')
							.data('type', obj.type)
							.data('val', obj.value)
							.data('useRegex', obj.regex)
					)
				);
				$ele.append($row);
			}
		}

		function initOptionsPanel() {
			if (window.Options && !Options.get_tab('filter')) {
				Options.add_tab('filter', 'list', _('Filters'));
				Options.extend_tab('filter',
					'<div id="filter-control">' +
						'<select>' +
							'<option value="name">'+_('Name')+'</option>' +
							'<option value="trip">'+_('Tripcode')+'</option>' +
							'<option value="sub">'+_('Subject')+'</option>' +
							'<option value="com">'+_('Comment')+'</option>' +
						'</select>' +
						'<input type="text">' +
						'<input type="checkbox">' +
						'regex ' +
						'<button id="set-filter">'+_('Add')+'</button>' +
						'<button id="clear">'+_('Clear all filters')+'</button>' +
						'<div id="confirm" class="hidden">' +
							_('This will clear all filtering rules including hidden posts.')+' <a id="confirm-y" href="#">'+_('yes')+'</a> | <a id="confirm-n" href="#">'+_('no')+'</a>' +
						'</div>' +
					'</div>' +
					'<div id="filter-container"><table id="filter-list"></table></div>'
				);
				drawFilterList();

				// control buttons
				$('#filter-control').on('click', '#set-filter', function () {
					var type = $('#filter-control select option:selected').val();
					var value = $('#filter-control input[type=text]').val();
					var useRegex = $('#filter-control input[type=checkbox]').prop('checked');

					//clear the input form
					$('#filter-control input[type=text]').val('');

					addFilter(type, value, useRegex);
					drawFilterList();
				});
				$('#filter-control').on('click', '#clear', function () {
					$('#filter-control #clear').addClass('hidden');
					$('#filter-control #confirm').removeClass('hidden');
				});
				$('#filter-control').on('click', '#confirm-y', function (e) {
					e.preventDefault();

					$('#filter-control #clear').removeClass('hidden');
					$('#filter-control #confirm').addClass('hidden');
					setList({
						generalFilter: [],
						postFilter: {},
						nextPurge: {},
						lastPurge: timestamp()
					});
					drawFilterList();
				});
				$('#filter-control').on('click', '#confirm-n', function (e) {
					e.preventDefault();

					$('#filter-control #clear').removeClass('hidden');
					$('#filter-control #confirm').addClass('hidden');
				});


				// remove button
				$('#filter-list').on('click', '.del-btn', function (e) {
					e.preventDefault();

					var $ele = $(e.target);
					var type = $ele.data('type');
					var val = $ele.data('val');
					var useRegex = $ele.data('useRegex');

					removeFilter(type, val, useRegex);
				});
			}
		}

		/* 
		 *  clear out pruned threads
		 */
		function purge() {
			var list = getList();
			var board, thread, boardId, threadId;
			var deferred;
			var requestArray = [];

			var successHandler = function (boardId, threadId) {
				return function () {
					// thread still alive, keep it in the list and increase the time between checks.
					var list = getList();
					var thread = list.nextPurge[boardId][threadId];

					thread.timestamp = timestamp();
					thread.interval = Math.floor(thread.interval * 1.5);
					setList(list);
				};
			};
			var errorHandler = function (boardId, threadId) {
				return function (xhr) {
					if (xhr.status == 404) {
						var list = getList();

						delete list.nextPurge[boardId][threadId];
						delete list.postFilter[boardId][threadId];
						if ($.isEmptyObject(list.nextPurge[boardId])) delete list.nextPurge[boardId];
						if ($.isEmptyObject(list.postFilter[boardId])) delete list.postFilter[boardId];
						setList(list);
					}
				};
			};

			if ((timestamp() - list.lastPurge) < 86400)  // less than 1 day
				return;
			
			for (boardId in list.nextPurge) {
				board = list.nextPurge[boardId];
				for (threadId in board) {
					thread = board[threadId];
					if (timestamp() > (thread.timestamp + thread.interval)) {
						// check if thread is pruned
						deferred = $.ajax({
							cache: false,
							url: '/'+ boardId +'/res/'+ threadId +'.json',
							success: successHandler(boardId, threadId),
							error: errorHandler(boardId, threadId)
						});
						requestArray.push(deferred);
					}
				}
			}

			// when all requests complete
			$.when.apply($, requestArray).always(function () {
				var list = getList();
				list.lastPurge = timestamp();
				setList(list);
			});
		}

		function init() {
			if (typeof localStorage.postFilter === 'undefined') {
				localStorage.postFilter = JSON.stringify({
					generalFilter: [],
					postFilter: {},
					nextPurge: {},
					lastPurge: timestamp()
				});
			}

			var pageData = {
				boardId: board_name,  // get the id from the global variable
				localList: [],  // all the blacklisted post IDs or UIDs that apply to the current page
				noReplyList: [],  // any posts that replies to the contents of this list shall be hidden
				hasUID: (document.getElementsByClassName('poster_id').length > 0),
				forcedAnon: ($('th:contains(Name)').length === 0)  // tests by looking for the Name label on the reply form
			};

			initStyle();
			initOptionsPanel();
			initPostMenu(pageData);
			filterPage(pageData);

			// on new posts
			$(document).on('new_post', function (e, post) {
				var threadId;

				if ($(post).hasClass('reply')) {
					threadId = $(post).parents('.thread').attr('id').replace('thread_', '');
				} else {
					threadId = $(post).attr('id').replace('thread_', '');
					post = $(post).children('.op')[0];
				}

				filter(post, threadId, pageData);
				quickToggle(post, threadId, pageData);
			});

			$(document).on('filter_page', function () {
				filterPage(pageData);
			});

			// shift+click on catalog to hide thread
			if (active_page == 'catalog') {
				$(document).on('click', '.mix', function(e) {
					if (e.shiftKey) {
						var threadId = $(this).data('id').toString();
						var postId = threadId;
						blacklist.add.post(pageData.boardId, threadId, postId, false);
					}
				});
			}

			// clear out the old threads
			purge();
		}
		init();
	});
	
	if (typeof window.Menu !== "undefined") {
		$(document).trigger('menu_ready');
	}
}

Mass reply

This is now included in Sharty Fixes

Reply to everyone in a thread.

Expand to view the script

// ==UserScript==
// @name         Mass Reply for soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Mass reply
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
(function () {
  function insert_after(new_node, ref_node) {
    ref_node.parentNode.insertBefore(new_node, ref_node.nextSibling);
  }
  function mass_reply() {
    let form_textarea = document.getElementById('body');
 
    let post_no_nodes = document.getElementsByClassName("post_no");
    for(const node of post_no_nodes) {
      let post_no_text = node.textContent;
      if(!post_no_text.includes("No")) {
        form_textarea.value += `>>${post_no_text}\n`;
      }
    }
    form_textarea.focus();
  }
  
  function add_button() {
    let ref_node = document.querySelectorAll(".op .intro .post_no")[1];
    let button = document.createElement("input");
    button.type = "button";
    button.value = "Mass Reply";
    button.style.marginLeft = "5px";
    button.addEventListener("click", function() {
      mass_reply();
    }, false);
    
    insert_after(button, ref_node);
  }
  
  add_button();
})();

Wojakificator

Wojakificator is a JS script made by a bunkerchan user that automatically quotes any post you want an attaches a soyjak image

The script might work using User JS option, but it is recommended to use a userscript manager like Violentmonkey instead

Source code

Warning: includes some lefty and NAS images

Expand to view the script

Download link

Anti 4channeler posts

Hides posts made by 4channelers.

Warning: Updates the page every 4 seconds to check for new posts, can be adjusted.

Expand to view the script

// ==UserScript==
// @name         Anti 4channeler posts on soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Hides 4channeler posts
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
let posts = document.querySelectorAll('.body');
let replies = document.querySelectorAll(".replies");
keys= [
   "newfag",
   "fag",
   "gem",
   "faggot",
   "new fag",
   "newfren",
   "newfrien",
   "chud",
   "frogposter",
   "nas",
   "kys",
   "killyourself",
   "go back",
   "goback",
   "reddit",
   "kill yourself",
   "hang",
   "coal",
   "reddit frog",
    "frog",
    "what does the reddit",
    "frog has to do with",
     "redditfrog",
     "frogtranny",
"nigger",
    "tranny"
]
function containsNonLatinCodepoints(s) {
    return /[^\u0000-\u00ff]/.test(s);
}
function start_filtering()
{
posts = document.querySelectorAll('.body');
replies = document.querySelectorAll(".replies");
for(let i =0 ; i<posts.length;i++)
{
for(let j=0;j<keys.length;j++)
{
  if(posts[i].innerHTML.toLowerCase().includes(keys[j].toLowerCase()) || containsNonLatinCodepoints(posts[i].innerHTML.toLowerCase()) == true )
{
posts[i].innerHTML= "<span style='color:green;font-weight:bold;font-size:14px;'>[HIDDEN 4channeler post]</span>";
}
}
 
}

for(let i =0 ; i<replies.length;i++)
{
for(let j=0;j<keys.length;j++)
{
  if(replies[i].innerHTML.toLowerCase().includes(keys[j].toLowerCase()))
{
replies[i].innerHTML= "<span style='color:green;font-weight:bold;font-size:14px;'>[HIDDEN 4channeler post]</span>";
}
}
 
}

}

start_filtering();
setInterval(start_filtering,2000);
//Interval


//Gifs hider
document.querySelectorAll("img").forEach(i=>{if(i.src.includes(".gif")){i.src="";}});

Preview for Youtube Videos

Show preview for youtube video links.

Expand to view the script

// ==UserScript==
// @name         YouTube preview for soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Previews YouTube videos
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
(function youtubeInlinePreviews() {

const re = /(?:youtube\.com\/watch\?v=|youtu\.be\/)(.{11})/;

const previewTemplate = (videoId) => `<img

style="max-width:255px;max-height:255px"

src="https://i.ytimg.com/vi/${videoId}/hqdefault.jpg"

/>`;

Array.from(document.querySelectorAll(".body a"))

.filter((link) => link.href.match(re))

.forEach((link) => {

const videoId = link.href.match(re)[1];

const inlinePreview = previewTemplate(videoId);

link.innerHTML = inlinePreview;

});

})();

Filter tripchuds

To use it, change "!!TRIP GOES HERE" to any trip you want to filter (ex: !incelchud1 or !!incelchud1), can also be used to filter names if you change

(/class="trip">!!TRIP GOES HERE</)

to

(/class="name">name of the chudcel you want to filter</)

if you want to filter multiple tripchuds, you have to do this

(/class="trip">!!FIRST TRIP CHUD|!SECOND TRIPCHUD|!THIRD TRIPCHUD</)

Expand to view the script

// ==UserScript==
// @name         Tripfag filter for soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Filters tripfags
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
$(".post")
  .filter(function (index) {
    return this.innerHTML.match(/class="trip">!!TRIP GOES HERE</);
  })
  .each(function (index) {
    let whatToHide = "#" + this.id;
    if (this.id.startsWith("op_")) {
      whatToHide = "#" + this.id.replace("op_", "thread_");
    }
    $(whatToHide).hide();
  });

if (!localStorage.favorites) {
	localStorage.favorites = '[]';
}

Hide tripchud posts from catalog

Hides all tripchud posts from catalog, no exceptions.

Expand to view the script

// ==UserScript==
// @name         Tripfag catalog filter for soyjak.party
// @namespace    datamining
// @version      0.1
// @description  Filters tripfags
// @author       Chud (You)
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
// --- start: purgeTripsFromCatalog ---

(function purgeTripsFromCatalog() {
  // If on a catalog page
  if (document.location.href.match(/catalog\.html$/)) {
    // Call the API for that page
    fetch(document.location.href.replace(".html", ".json"))
      .then((res) => res.json())
      .then((json) =>
        json
          // Find the threads where OP is using a tripcode
          .reduce((acc, cur) => [...acc, ...cur.threads], [])
          .filter((op) => op.trip)
          // Hide them
          .forEach((filtered) => $(`div[data-id='${filtered.no}']`).hide())
      );
  }
})();

// --- end: purgeTripsFromCatalog ---

Disable gif autoplay

Expand to view the script

// ==UserScript==
// @name     disable gif autoplay
// @version  1
// @grant    none
// @match https://soyjak.party/*
// ==/UserScript==

window.addEventListener('load', function () {
[].slice.apply(document.images).filter(is_gif_image).map(freeze_gif);

function is_gif_image(i) {
    return /^(?!data:).*\.gif/i.test(i.src);
}

function freeze_gif(i) {
    var c = document.createElement('canvas');
    var w = c.width = i.width;
    var h = c.height = i.height;
    c.getContext('2d').drawImage(i, 0, 0, w, h);
    try {
        i.src = c.toDataURL("image/gif");
    } catch(e) {
        for (var j = 0, a; a = i.attributes[j]; j++)
            c.setAttribute(a.name, a.value);
        i.parentNode.replaceChild(c, i);
    }
}
})

Ratio script

adds a [ratio] button that starts posting automated replies from a selection of 4 types: "generic","cob","trans" and "chud". perfect for shitposting

(feel free to add more quotes to the code, the "chud" one is very incomplete)

// ==UserScript==
// @name        Sharty Ratio
// @namespace   soyjak.party
// @match       http*://soyjak.party/*
// @version     1.0
// @author      God Tier Wojack
// @description Ratio that nigga
// ==/UserScript==
const modifiers = ["==", "%%", "--", "'", ""];
let done = new Array(20);
let stringSets = {
  "Generic": ["holy shit", "holy shiiiit", "holy fuck", "holy fuck.", "fuckin hell", "holy fuckk", "holy fuckkk", "holy fuckkkk", "lfg", "lfggg", "lfgggg", "lfg!", "lfg!!", "lfgg!!!", "w", "dub", "massive w", "huge w", "gigantic w", "massive dub", "huge dub", "another dub", "another w", "gigantic w", "get his ass", "get that nigga", "lets fucking go", "lets fucking gooo", "lets fucking goooo", "lets fucking goooo", "lets fucking go!", "lets fucking go!!", "lets fucking go!!!", "lets fucking go!!!!!", "yo get his ass", "yo get em", "yooo", "yoooo", "yooooooo", "yoooooooooooo", "god damn", "got damn", "god damnnn", "damnnnnn", "own that fraud", "expose that fraud", "lets gooo", "lets gooooo", "let's goooooo", "keyed", "keyed af", "holy keyed", "gem", "massive gem", "gemerald", "wem", "huge gem", "gigantic gem", "sharty saving gem", "diamond", "sharty saving diamond", "up", "go up", "go the fuck up", "up up up", "go tf up", "'chup", "own that fraud", "get they ass", "beat his ass", "kill that nigga", "can't stop winning", "we cant stop winning bros", "diamonderald", "btfo", "zamn", "zamnnn", "holy based", "based af", "GYATT", "GYAT DAYUM", "DAMN ZIGGA", "GET THAT NIGGA", "NIGGA", "COOK THAT NIGGA", "let him cook", "HUUUUUUUUUGE FUCKING COCK", "GET OUT DA HOOD", "DAYUM NIGGA", "WHAT DA HEEEEEEEEEEEEEEEEEEELL", "COOK HIS ASS", "EAT THAT NIGGA", "HUGE GYATT", "RIZZ", "ENORMOUS W", "W CHAT", "EAT HIS ASS", "How will he ever recover?", "#PACKWATCH", "AYO", "MOG HIS ASS", "LOCK IN", "VICTORY", "GOTTEM", "How will bro ever recover?", "How will blud ever recover?", "BRO WILL NEVER RECOVER", "BLUD WILL NEVER RECOVER", "check'd and kek'd", "BUMP"],
  "Cob": ["another cob w", "#cobgang", "another gemson victory", "gemson win", "gemson victory", "gemson up", "god tier wojack", "gem tier godjack", "cobby up", "cobby go up", "godson up", "upson", "keyedson", "winson", "cob w", "cob dub", "cobby win", "#cobgang win", "#cobgang victory", "hwabag", "god tier winjack", "diamondson go up", "winson up", "gemson go up", "godson go up", "gemson dub", "gemson w", "godson dub", "godson w", "#cobgang dub", "#cobgang w", "cobwin", "he won", "he fucking won", "he cant stop winning"],
  "Trans": ["trans rights", "trans fucking rights", "trans rights won", "sisters...", "trans rights w", "trans rights dub", "trans folx won", "w trans rights", "trans rights go up", "transphobes btfo", "transphobes destroyed", "trans rights victory", "w for trans rights", "trans victory", "transerald", "trans diamond", "bump up the trans", "uptrans", "sisters go up", "upsis", "trans top", "estrogem", "estrogemerald", "bumpstrogen", "topstrogen", "winstrogen"],
   "chud":["1488","fuck niggers","kill all blacks","kanye 2024","dial eight","-ACK!","sieg heil!","jews","media is kiked","goyslop","hang yourself troon","the west has fallen","back to /leftypol/","amerimutt","women are made for rape"]
}
let targetPosts = [];
let sets = [stringSets["Generic"]];
setInterval(() => {
  document.querySelectorAll(".button.alert_button").forEach(e => e.click());
  if (targetPosts.length == 0 || sets.length == 0) {
    return;
  }
  let post = "";
  targetPosts.forEach(p => post += `>>${p}\n`);
  let effect = "";
  if (Math.random() > 0.5) {
    effect = modifiers[Math.floor(Math.random() * modifiers.length)];
  }
  post += effect;
  let strings = sets.flat();
  stringsLength = strings.length;
  let found = false;
  while (!found) {
    text = strings[(Math.floor(Math.random() * stringsLength))];
    if (!done.includes(text)) {
      if (Math.random() > 0.5) {
        text = text.toUpperCase();
      }
      post += text;
      found = true;
      done.unshift(text);
      done.pop();
    }
  }
  post += effect;
  document.querySelector("form[name=post] textarea#body").value = post;
  document.querySelector("form[name=post] input[value*='Reply']").click();
}, 12000);
function addRatioButton(post) {
  post.querySelector(".intro").insertAdjacentHTML("beforeend", `<a href="javascript:void(0);" class="ratio" postNumber="${post.getElementsByClassName("post_no")[1].textContent}">[Ratio]</a>`);
}
let options = Options.add_tab("ratio", "gear", "Ratio").content[0];
let optionsHTML = "";
for ([key, value] of Object.entries(stringSets)) {
  optionsHTML += `<input type="checkbox" id="ratio-${key}" name="${key}"><label for="ratio-${key}">${key}</label><br>`;
}
options.insertAdjacentHTML("beforeend", optionsHTML);
options.querySelectorAll("input[type=checkbox]").forEach(e => {
  e.addEventListener("change", e => {
    sets = [];
    options.querySelectorAll("input[type=checkbox]:checked").forEach(c => sets.push(stringSets[c.getAttribute("name")]));
  });
  e.checked = e.getAttribute("name") == "Generic";
});
const updateObserver = new MutationObserver(list => {
  list.forEach(node => {
    if (node.addedNodes[0].nodeName == "DIV") {
      addRatioButton(node.addedNodes[0]);
    }
  });
});
updateObserver.observe(document.querySelector(".thread"), {
  childList: true
});
[...document.getElementsByClassName("post")].forEach(e => {
  addRatioButton(e);
});
document.addEventListener("click", e => {
  let t = e.target;
  if (t.classList.contains("ratio")) {
    if (t.textContent == "[Ratio]") {
      t.textContent = "[Unratio]";
      targetPosts.push(t.getAttribute("postNumber"));
    } else {
      targetPosts = targetPosts.filter(p => p != t.getAttribute("postNumber"));
      t.textContent = "[Ratio]";
    }
  }
});

Thremboify

Converts post numbers to Base 11 with Thrembo (Ϫ)

Expand to view the script

// ==UserScript==
// @name         Soyjak.party Thremboify
// @namespace    http://soyjak.party/
// @version      0.1
// @description  Thremboifies post numbers on Soyjak.party
// @author       Chud
// @match        https://soyjak.party/*
// @grant        none
// ==/UserScript==
const thr_lut = ['0', '1', '2', '3', '4', '5', '6', 'Ϫ', '7', '8', '9'];
function thr_cnv(num) {
  if (num === 0) {
    return '0';
  }
  let result = '';
  while (num !== 0) {
    const remainder = num % 11;
    result = thr_lut[remainder] + result;
    num = Math.floor(num / 11);
  }
  return result;
}
function thr_up() {
    console.log('updating');
    document.querySelectorAll('.post_no').forEach((el) => {
        if (el.classList.contains('thr_ok')) { return; }
        el.classList.add('thr_ok');
        if (el.innerText == '№') { return; }
        const res = thr_cnv(parseInt(el.innerText));
        el.innerText = res;
    });
    document.querySelectorAll('a[class^="mentioned-"]').forEach((el) => {
        if (el.classList.contains('thr_ok')) { return; }
        el.classList.add('thr_ok');
        const res = thr_cnv(parseInt(el.innerText.substring(2)));
        el.innerText = `>>${res}`;
    });
    document.querySelectorAll('a[onclick^="highlightReply"][href*="/thread"]').forEach((el) => {
        if (el.classList.contains('thr_ok')) { return; }
        el.classList.add('thr_ok');
        if (el.innerText == '№') { return; }
        const res = thr_cnv(parseInt(el.innerText.substring(2)));
        el.innerText = `>>${res}`;
    });
}
const observer = new MutationObserver((mutationsList, observer) => {
    for (let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            thr_up();
            return;
        }
    }
});
const config = { childList: true, subtree: true };
observer.observe(document.body, config);
thr_up();

Hide Website Origin

Useful for hiding the fact that you came from the ‘arty if you’ve clicked a link on the ‘ty for a site that you wish to raid (e.g. an altchan).

Expand to view the script

const referrerPolicy = document.createElement("meta")
referrerPolicy.setAttribute("name", "referrer")
referrerPolicy.setAttribute("content", "same-origin")
document.querySelector("head").appendChild(referrerPolicy)

Sharty GET Stealer

Self-explanatory.

Grab it from https://greasyfork.org/en/scripts/470562-get-stealer

4cuck GET Stealer

It’s on the GET page, chud

Change Banner on Click

Makes the banner image change when clicked, useful for quickly cycling through them to find a certain one.

document.querySelector(".board_image").setAttribute("onClick", `document.querySelector(".board_image").setAttribute("src", "/b.php#" + new Date().getTime());`);

Redirect Broken /res/ URLs to /thread/ URLs

Redirects thread URLs in the old soyjak.party/*/res/*.html format to the current soyjak.party/*/thread/*.html format.

Very niche these days since the formatting change was made mid Kuz-era but it's useful when using 4chan-x on the sharty as it's thread watcher serves /res/ URLs.

Expand to view the script

// ==UserScript==
// @name        soyjak.party - Fix /res/ links
// @namespace   caca
// @match       https://soyjak.party/*/res/*.html
// @grant       none
// @version     0.1
// @author      newGOD
// @description Redirect old /res/ links to the new /thread/ link format
// ==/UserScript==
location = location.href.replace("res", "thread")


CSS

In addition to user JS, soyjak.party also offers an option to customize user CSS.


Many CSS styles can be found on https://github.com/vichan-devel/vichan/tree/master/stylesheets, and https://github.com/lainchan/lainchan/tree/master/stylesheets.

Built into soyjak.party, a theme featuring a gay furry fox, Polish internet's enclave on all imageboards using vichan.[1]

Soyjak.party also inherits from Vichan many built-in themes. The complete list of themes can be found in the vichan source code. The themes are unlisted but can be added by name like this:

@import "https://soyjak.party/stylesheets/rugby.css";


Custom underwater theme

The underwater theme in use

Adds marine life to your browsing experience

firstly, add this to your User CSS

Expand to view the script

/**
 * miku.css
 * For AwsumChan by Circlepuller
 */
body {
background: #D2FFEE url('img/fade-miku.png') top repeat-x;
}

a:link, a:visited {
text-decoration: none;
color: #00637B;
}

a:link:hover, a:visited:hover {
color: #DD0000;
}

a.post_no {
color: #000033;
}

.intro a.email span.name {
color: #0093AB;
}

.intro a.email:hover span.name {
color: #DD0000;
}

h2, div.title, h1 {
color: #800000;
}

form table tr th {
background: #95D2D3;
}

div.banner {
background-color: #E04000;
}

div.post.op hr {
border-color: #B7C9D5;
}

.intro span.subject {
color: #117743;
font-weight: 800;
}

.intro span.name {
color: #117743;
font-weight: 800;
}

div.post.reply.highlighted {
background: #a9d8ff;
}

div.post.reply {
background: #B6DDDE;
border-color: #8FCCCD;
}

div.ban {
border: 1px solid #0093AB;
}

div.ban h2 {
background: #B6DDDE;
color: #0093AB;
}

div.pages {
color: #8899AA;
background: #B6DDDE;
border-right: 1px solid #8FCCCD;
border-bottom: 1px solid #8FCCCD;
}

hr {
border-color: #B7D9C5;
}

div.boardlist {
color: #0093AB;
    background-color: rgba(65%, 85%, 95%, 0.2);
}

.desktop-style div.boardlist:nth-child(1) {
  text-shadow: #D2FFEE 1px 1px 1px, #D2FFEE -1px -1px 1px;
}
* {
   background-image: url('https://files.catbox.moe/hp03xs.png');
}

.soifish {
   background-image: url('https://files.catbox.moe/rxmvyr.png');
   position: fixed;
    pointer-events: none;
  -webkit-animation: moveX 30s linear 0s infinite alternate, moveY 30s linear 0s infinite alternate;
  -moz-animation: moveX 30s linear 0s infinite alternate, moveY 30s linear 0s infinite alternate;
  -o-animation: moveX 30s linear 0s infinite alternate, moveY 30s linear 0s infinite alternate;
  animation: moveX 30s linear 0s infinite alternate, moveY 30s linear 0s infinite alternate;
}

@-webkit-keyframes moveX {
  from { left: 0; } to { left: 100%; }
}
@-moz-keyframes moveX {
  from { left: 0; } to { left: 100%; }
}
@-o-keyframes moveX {
  from { left: 0; } to { left: 100%; }
}
@keyframes moveX {
  from { left: 0; } to { left: 100%; }
}

@-webkit-keyframes moveY {
  from { top: 0; } to { top: 100%; }
}
@-moz-keyframes moveY {
  from { top: 0; } to { top: 100%; }
}
@-o-keyframes moveY {
  from { top: 0; } to { top: 100%; }
}
@keyframes moveY {
  from { top: 0; } to { top: 100%; }
}



.post.reply .body a:hover:after {
    content: url(https://soyjak.download/f.php?h=0lnyi5TW&p=1);
    display: block;
    position: absolute;
    left: 20px;
    top: -255px;
    pointer-events: none;
    z-index: 999;
}

.post.reply .body a:hover {
    position: relative;
}

body:after {
    content: url(https://soyjak.download/f.php?h=3EFSgyRY&p=1);
    display: block;
    position: fixed;
    bottom: 0px;
    right: 0px;
    pointer-events: none;

.desktop-style div.boardlist:nth-child(1):hover, .desktop-style div.boardlist:nth-child(1).cb-menu {
  background-color: rgba(70%, 95%, 100%, 0.45);
}

Then add this to your User JS or Tampermonkey

// ==UserScript==
// @name         JS for Ocean Theme
// @namespace    datamining
// @version      0.1
// @description  Glub Glub Glub Glub
// @author       Glub
// @match        https://soyjak.party/*
// @icon         https://soyjak.party/static/favicon.png
// @grant        none
// ==/UserScript==
var soislug = document.createElement("img");
soislug.setAttribute('src', 'https://files.catbox.moe/vpoeyt.png');
soislug.setAttribute('class', 'soislug');
document.getElementsByClassName("8chan")[0].appendChild(soislug);
var soifish = document.createElement("img");
soifish.setAttribute('src', 'https://files.catbox.moe/rxmvyr.png');
soifish.setAttribute('class', 'soifish');
document.getElementsByClassName("8chan")[0].appendChild(soifish);

Custom Soot theme

Soot color scheme (grey and yellow) theme, this css should be used with dark style.

Expand to view the script

/*soot theme*/

.name {
    color: #FDD73A !important;
}

body {
    background: black url(https://i.imgur.com/FeQmhfL.png) right bottom no-repeat fixed;
}

div.post.reply {
    background-color: #646464 !important;
    color: black;
    border-radius:0;
}

div#post-moderation-fields , div#style-select {
    padding:4px;
    background-color:rgba(0,0,0,28);
}

span.heading {
    color: #FF565C !important;
}

.remove-btn {
    color: rgba(255,255,255,128) !important;
}

hr {
    border-color:transparent;
}

Feral Theme

body { 
   background: #ffdbd2;
   background-image: url(https://file.garden/ZCftkBQZY2RSmYgu/feral.png);
    background-position: bottom right;
    background-repeat: no-repeat;
    background-attachment: fixed;}


div.post.reply {
  color: #000;
  background: #eaa7a7;
  border-right: 2px solid #d9bfb7;
  border-bottom: 2px solid #d9bfb7;
}

div.post.reply.highlighted {
     background: #ec6464;
}

.desktop-style div.boardlist:nth-child(1) {
      background: #d85656 
}

div.boardlist a {
    color: #fff;
}

div.pages {
   background: #d85656 
}

Calm Theme

body {
    background: #fafcff;
    background-image: url(https://file.garden/ZCftkBQZY2RSmYgu/sdjasd); 
    background-position: bottom right;
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-size: 200px;
    
}

div.post.reply {
    background:  #fafcff url('/stylesheets/img/fade-blue.png')     margin: 0.3em 6px;
    padding: 0.2em 0.3em 0.5em 0.6em;
    border-width: 1px;
    border-style: none solid solid none;
    border-radius: 0.7em;
    box-shadow: 0.1rem 0.2rem 0.1rem 0.02rem rgba(1,2,3,.5)
 margin-top 20px;
}

div.post.reply div.body {
  overflow-y: auto;
  max-height: 70vh;


}

.intro span.name {
  font-style: italic;
  color: rgb(129, 123, 204);
}

.post-image { 
    box-shadow: 0.1rem 0.2rem 0.1rem 0.03rem rgba(0,0,0,.2);
}

h1 {
    font-family: tahoma;
    letter-spacing: -2px;
    font-size: 20pt;
    margin: 0;
    text-shadow: 20px;

}

header div.subtitle, h1 {
    color: #9cc3ff;
    text-align: center;
    text-shadow: 20px;
    font-family: Arial, Helvetica, sans-serif;


}

span.heading {
    color: #9a2ea1;
    font-size: 11pt;
    font-weight: bold;
}

div.blotter {
    color: #9cc3ff;
    text-align: center;
}

Doll Theme

.name {
    color:#FB4598 !important;
    
} 


div.post.reply.highlighted {a
     background: #d17dcd;;
}


.desktop-style div.boardlist:nth-child(1) {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    margin-top: 0;
    z-index: 30;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
    border-bottom: 1px solid;
    background-color: #c774ff;
    color: red
}




div.post.reply {
  color: #000;
   background: #e5a9db;
    border-right: 2px solid #d1a5d9;
    border-bottom: 2px solid #d1a5d9;
}
 

body {
    background: #fad7eb;
    background-image: url(https://file.garden/ZCftkBQZY2RSmYgu/doll.png);
    background-position: bottom right;
    background-repeat: no-repeat;
    background-attachment: fixed;
}
div.banner {
    background-color: #ff0034;

}
.name:before {
  content: 'Little '; }  
} 

Glow Theme

.post,
input,
textarea {
  border: 1px solid #040!important;
}

body {
  background-color: #000;
  color: #7f7!important;
  background-image: url("https://booru.soy/_images/125c6ba37329910a8f662c25f13b80e7/39652%20-%20SoyBooru.png");
  background-size: 200px;
  background-position: 100% 0;
  animation: 10s infinite anim;
}

.post {
  background: #020!important;
  color: #fff!important;
  box-shadow: 0 0 50px green;
}

.name,
a {
  color: #32cd32!important;
}

.post.highlighted {
  background: #030!important;
}

.name {
  position: relative;
}

.name:after {
  content: '## Fed';
  font-size: 14px;
  display: inline-block;
  color: #0f0;
  text-shadow: 0 0 8px #0f0;
  margin-left: .25em;
}

.boardlist {
  background: #040!important;
}

.quote,
h1,
h2,
h3,
h4,
h5 {
  color: #0f0!important;
}

@keyframes anim {
  0%, 100% {
    background-position: 100% 0;
  }
  50% {
    background-position: 100% -5%;
  }
}

body:after {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  background-image: url("https://booru.soy/_images/bfa5349f1fe25f685db1ed8973a3d864/2158%20-%20SoyBooru.png");
  background-repeat: no-repeat;
  background-position: 100% 100%;
  background-size: 150px;
}

input,
textarea {
  background: #030;
  color: #0f0;
}

textarea {
  background: #020;
  color: #fff;
}

.banner {
  background-color: transparent!important;
  color: #7f7!important;
}

#options_div {
  background-color: #020;
}

.options_tab_icon.active {
  color: #7f7;
}

.file-hint {
  color: #fff!important;
}

form table tr th {
  background: #020;
}

.dropzone {
  color: #7f7;
}

.dragover {
  background: #040!important;
}

Pear Theme

/*Pear theme*/

body {
background: #f4f1d0 url(https://file.garden/ZCftkBQZY2RSmYgu/transpear) right bottom no-repeat fixed;
}

div.post.reply {
background-color: #dee88f !important;
padding: 0.2em 0.3em 0.5em 0.6em;
border-width: 2px;
border-style: none solid solid none;
border-radius: 0.7em;
}

div#post-moderation-fields , div#style-select {
padding:4px;

}

span.heading {
color: #52a521 !important;
}

.desktop-style div.boardlist:nth-child(1) {
background: #f2eda6;
}

div.post.reply div.body a {
color: #62b532;
}

h1 {
color: #4a9d1b;
}

div.blotter {
color: green }

div.pages.top {
display: none;
}

div.pages {
background: #c2efb9;
}

Soyjak Theme


.intro span.name {
  color: #000000;
  font-weight: bold;
}

.desktop-style div.boardlist:nth-child(1) {
  box-shadow: 0 0px 0px;
  border-bottom: 0px solid;
  background: 0;
}

h1 {
color: #000000;
text-align: center;
}

div.blotter {
  color: #000000;
  font-weight: bold;
  text-align: center;
}

form table tr th {
  background: #fafafa;
}

div.post.reply.highlighted {a
     background: #fffff;
}

div.post.reply div.body {
  overflow-y: auto;
  max-height: 50vh;
}

div.post.reply {
  color: #000000;
   background: #fafafa;
    border-right: 2px solid #c9c9c9;
    border-bottom: 2px solid #c9c9c9;
}
 

body {
background-image: none;
background: #ffffff url('https://i.ibb.co/Xtb2fXF/fade.png') repeat-x 50% 0%;
}

div.banner {
  background: 0;
  color: #000000;
  font-size: 12pt;
  font-weight: bold;
  text-align: center;
  margin: 1em 0;
}

div.banner  a {
  color: #000000;
}

div.post.reply.highlighted {
  background: #efefef;
}

hr {
    border: none;
        border-top-color: currentcolor;
        border-top-style: none;
        border-top-width: medium;
    border-top: 1px solid #000000;
    height: 0;
    clear: left;
}

div.pages {
  background: 0;
  border: 0px solid;
}

#options_div, #alert_div {
  background-color: #ffffff;

}

}

April Fool's 2023

April Fool's 2023 theme. Makes the sharty look like Discord.

Expand to view the script

/* Fonts */
@font-face{font-family:'Discord';src:url('https://web.archive.org/web/20230401012547/https://s.kncdn.org/fonts/discord.otf') format('opentype');font-weight:normal;font-style:normal}

/* Body */
body{
	background-color:#313338;
	color:#fbfbfe;
	font-family:'Discord', Arial, sans-serif !important;
	font-size:11pt
}

/* Boardlist */
.boardlist{background-color:#313338 !important}

/* Posts */
div.post.reply{
	background-color:#313338;
	border:none
}

/* Post Numbers */
.name:before{content:"@"}
.name{
	background-color:#3d4270;
	color:#c8ccfa !important
}

/* File Info */
input[type=checkbox],p.fileinfo{display:none}

/* Text */
a,a:visited{color:#7289da}
time:after{content:", in #soy "}
div.post_no{
	background-color:#3d4270;
	font-family:Arial;
	font-size:10pt;
	color:#b9bdeb !important;
	font-weight:bold
}
div.banner{display:none}
input,textarea{
	background-color:#383a40;
	color:#ffffff;
	border:none !important;
	border-radius:5px
}

/* Top Bar */
div.pages.top{background:#313338 !important}

/* Headings */
.subject,h1,h2{color:#5563e9 !important}

/* Highlighted Post */
div.post.reply.highlighted{background:#2e3035}
div.post.reply div.body a{color:#7289da}

/* Seperator */
hr{border-top:1px solid #3f4147 !important}

/* Pages */
div.pages,span.heading,span.heading2{color:#5563e9}

/* Post Form */
form table tr th{background:#5563e9}

/* FileHint */
.dropzone .file-hint{
	color:rgb(114, 137, 218);
	cursor:pointer;
	position:relative;
	margin-bottom:5px;
	padding:10px 0;
	top:5px;
	transition:0.2s;
	border:2px dashed rgba(125, 125, 125, 0.4)
}

/* Post Images */
.post-image{border-radius:15px}

/* Post Numbers */
.post_no{font-family:Arial, Helvetica}

/* Blotter */
div.blotter{
	background-color: #2b2d31;
	border-radius: 25px;
	color: #b5bac1
}

Anti - mass reply

.post.reply > .body {
    max-height: 20em;
    overflow-y: auto;
}

Cobson in the corner

This code was briefly added to soyjak.party and is being left here for posterity.

Expand to view the script

body { background-image: url(https://soyjaks.party/cob3.png); background-position: bottom right; background-repeat: no-repeat; background-attachment: fixed;   background-size: 100px; }

Classic UI

Remove the visible "SAGE!" message

a[href^='mailto:sage']::after {
  content: ' SAGE!';
  text-decoration: none;
  display: none;
}

Return grid to catalog.


.theme-catalog div.thread img {
  float: none!important;
  margin: auto;
  max-height: 150px;
  max-width: 200px;
  box-shadow: 0 0 4px rgba(0,0,0,0.55);
  border: 2px solid rgba(153,153,153,0);
}

.theme-catalog div.thread {
  display: inline-block;
  vertical-align: top;
  text-align: center;
  font-weight: normal;
  margin-top: 2px;
  margin-bottom: 2px;
  padding: 2px;
  height: 300px;
  width: 205px;
  overflow: hidden;
  position: relative;
  font-size: 11px;
  max-height: 300px;
  background: rgba(182,182,182,0.12);
  border: 2px solid rgba(111,111,111,0.34);
}

.theme-catalog div.thread strong {
  display: block;
}

.theme-catalog div.threads {
  text-align: center;
  margin-left: -20px;
}

.theme-catalog div.thread:hover {
  background: #D6DAF0;
  border-color: #B7C5D9;
}

.theme-catalog div.grid-size-vsmall img {
  max-height: 33%;
  max-width: 95%
}

.theme-catalog div.grid-size-vsmall {
  min-width:90px; max-width: 90px;
  max-height: 148px;
}

.theme-catalog div.grid-size-small img {
  max-height: 33%;
  max-width: 95%
}

.theme-catalog div.grid-size-small {
  min-width:140px; max-width: 140px;
  max-height: 192px;
}

.theme-catalog div.grid-size-large img {
  max-height: 40%;
  max-width: 95%
}

.theme-catalog div.grid-size-large {
  min-width: 256px; max-width: 256px;
  max-height: 384px;
}

.theme-catalog img.thread-image {
  height: auto;
  max-width: 100%;
}

@media (max-width: 420px) {
  .theme-catalog ul#Grid {
    padding-left: 18px;
  }

  .theme-catalog div.thread {
    width: auto;
    margin-left: 0;
    margin-right: 0;
  }

  .theme-catalog div.threads {
    overflow: hidden;
  }
}

Christmas Hats

[data-board] > .files > :nth-child(1):not(.multifile) > a:before {
	content: url('https://s.kncdn.org/image/hat2.gif');
	float: left;
	display: block;
	margin-right: -160px;
	position: relative;
	top: -120px;
	left: -30px;
	
}
[data-board] > .files > :nth-child(1).multifile > a:before {
	content: url('https://s.kncdn.org/image/hat2.gif');
	float: left;
	display: block;
	margin-right: -160px;
	position: relative;
	top: -120px;
	left: -50px;
	
}

Crazy

html,p{color:#fa412a}*{transition:7.13s;font-family:'Comic Sans MS','Times New Roman',Times,serif;border:1px solid #000;background-color:#f0f;animation:.5s infinite shake,10s infinite colorchange}html{background:linear-gradient(to right,#4a412a,#fa412a,#f0f);text-shadow:2px 2px 2px #000}a{color:#1a412a;font-size:30px;text-decoration:underline;animation:.5s infinite shake,10s infinite colorchange,2s infinite alternate grow}@keyframes shake{0%,100%{transform:translateX(0)}10%,30%,50%,70%,90%{transform:translateX(-10px)}20%,40%,60%,80%{transform:translateX(10px)}}@keyframes colorchange{0%,100%{color:#fa412a}25%,75%{color:#f0f}50%{color:#1a412a}}@keyframes grow{0%{transform:scale(1)}100%{transform:scale(1.2)}}a:hover{color:#f0f;font-size:48px;filter:blur(3px)}p{text-transform:uppercase}p:hover{color:#f0f;font-size:72px;transform:scale(1.2)}


Citations