Page MenuHomePhorge

No OneTemporary

Size
21 KB
Referenced Files
None
Subscribers
None
diff --git a/instance/pleroma-mods/pleroma-mod-catify/config.json b/instance/pleroma-mods/pleroma-mod-catify/config.json
index 2aac73625c..31e19ede13 100644
--- a/instance/pleroma-mods/pleroma-mod-catify/config.json
+++ b/instance/pleroma-mods/pleroma-mod-catify/config.json
@@ -1,58 +1,78 @@
{
"nya": {
"enabled": true,
"matcher": "(^|\\s|>)な+(\\s|<|$)",
"replacer": {
"source": "な",
"dest": "にゃ"
}
},
"triggers": {
- "displayName": [
- "🐱",
- "😺",
- "🐈",
- "😼",
- "😹",
- "にゃ",
- "cat",
- "mew",
- "meow",
- "nya",
- "miaou",
- "miau",
- "kitten",
- "kitn",
- "ktn",
- "kadse",
- "catte",
- "makemeneko",
- "🔒",
- "waifu",
- "zonk",
- "neko",
- "anime",
- "red",
- "bot",
- "moe",
- "jason",
- "admiral",
- "corona",
- "lumeinshin",
- "coomer",
- "famardy",
- "matrix",
- "iji",
- "lewd",
- "deviant",
- "disabled"
- ],
- "instances": [
- "misskey.io",
- "fedi.absturztau.be",
- "catgirl.life",
- "freespeechextremist.com",
- "blob.cat"
- ]
+ "cat": {
+ "displayName": [
+ "🐱",
+ "😺",
+ "🐈",
+ "😼",
+ "😹",
+ "にゃ",
+ "cat",
+ "mew",
+ "meow",
+ "nya",
+ "miaou",
+ "miau",
+ "kitten",
+ "kitn",
+ "ktn",
+ "kadse",
+ "catte",
+ "makemeneko",
+ "🔒",
+ "waifu",
+ "zonk",
+ "neko",
+ "anime",
+ "red",
+ "bot",
+ "moe",
+ "jason",
+ "admiral",
+ "corona",
+ "lumeinshin",
+ "coomer",
+ "famardy",
+ "matrix",
+ "iji",
+ "lewd",
+ "deviant",
+ "disabled"
+ ],
+ "instances": [
+ "misskey.io",
+ "fedi.absturztau.be",
+ "catgirl.life",
+ "freespeechextremist.com",
+ "blob.cat"
+ ]
+ },
+ "bear": {
+ "displayName": [
+ "🐻"
+ ],
+ "instances": []
+ },
+ "rabbit": {
+ "displayName": [
+ "🐰",
+ "🐇",
+ "rabbit",
+ "bun",
+ "hase",
+ "häschen",
+ "kaninchen"
+ ],
+ "instances": []
+ }
}
}
diff --git a/instance/pleroma-mods/pleroma-mod-catify/mod.js b/instance/pleroma-mods/pleroma-mod-catify/mod.js
index 3f34191c1a..1f549aa9fd 100644
--- a/instance/pleroma-mods/pleroma-mod-catify/mod.js
+++ b/instance/pleroma-mods/pleroma-mod-catify/mod.js
@@ -1,350 +1,389 @@
function ColorDetector (image) {
this.color = { r: 0, g: 0, b: 0 };
this.image = image;
}
[
function componentToHex (c) {
var hex = Math.max(Math.min(c, 255), 0).toString(16);
return hex.length === 1 ? "0" + hex : hex;
},
function getHexColor (offset) {
if (!offset) {
offset = { r: 0, g: 0, b: 0 };
}
return "#" +
this.componentToHex(this.color.r + offset.r) +
this.componentToHex(this.color.g + offset.g) +
this.componentToHex(this.color.b + offset.b);
},
function detect () {
return new Promise((resolve) => {
let blockSize = 5;
const canvas = document.createElement("canvas");
const context = canvas.getContext && canvas.getContext("2d");
let data; let width; let height;
let i = -4;
let rgb = { r: 0, g: 0, b: 0 };
let length;
let count = 0;
if (!context) {
console.warn("can't get context of avatar");
resolve(this.color);
return;
}
height = canvas.height = this.image.naturalHeight || this.image.offsetHeight || this.image.height;
width = canvas.width = this.image.naturalWidth || this.image.offsetWidth || this.image.width;
context.drawImage(this.image, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch (e) {
console.error("can't get image data");
console.error(e);
resolve(this.color);
return;
}
length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
this.color.r = ~~(rgb.r / count);
this.color.g = ~~(rgb.g / count);
this.color.b = ~~(rgb.b / count);
resolve(this.color);
});
}
].forEach((fn) => { ColorDetector.prototype[fn.name] = fn; });
-function PleromaCat (handle) {
+function PleromaCat (handle, type) {
+ this.type = type || "cat";
this.handle = handle;
this.colors = {
backgroundColor: "#000000",
borderColor: "#000000"
};
this.config = {
"nya": {
enabled: true,
matcher: "(^|\s|>)な+(\s|<|$)", // eslint-disable-line no-useless-escape
replacer: {
source: "な",
dest: "にゃ"
}
}
};
this.loadConfig();
}
[
function loadConfig () {
const json = PleromaModCatify.config;
if (!json.nya) {
return;
}
this.config.nya.enabled = json.nya.enabled;
if (this.config.nya.enabled) {
this.config.nya.matcher = json.nya.matcher || this.config.nya.matcher;
this.config.nya.replacer.source = json.nya.replacer.source || this.config.nya.replacer.source;
this.config.nya.replacer.dest = json.nya.replacer.dest || this.config.nya.replacer.dest;
}
},
function getClassName () {
return "USER____" + this.handle.replace(/@/g, "_AT_").replace(/\./g, "_");
},
function makeCat (element) {
if (!element) {
element = document;
}
if (element.querySelectorAll) {
var posts = element.querySelectorAll("." + this.getClassName());
this.makeCatByClassName("user-info");
this.makeCatByClassName("basic-user-card", "basic-user-card-screen-name");
for (const currentPost of posts) {
this.makeCatByElement(currentPost);
this.nyaByPost(currentPost);
}
}
},
function makeCatByClassName (className, usernameClass) {
if (!className) {
className = "user-info";
}
if (!usernameClass) {
usernameClass = "user-screen-name";
}
const userinfos = document.querySelectorAll("." + className);
for (const infoIndex in userinfos) {
if (userinfos[infoIndex].querySelector && !/cat$/.test(userinfos[infoIndex].innerText)) {
const handle = userinfos[infoIndex].querySelector("." + usernameClass);
const regexHandle = new RegExp(this.handle, "i");
if (handle) {
if (regexHandle.test(handle.innerText)) {
this.makeCatByElement(userinfos[infoIndex]);
}
}
}
}
},
function makeCatByElement (element) {
if (element.querySelectorAll) {
- if (!/cat$/.test(element.className)) {
- element.className += " cat";
- }
- const avatars = element.querySelectorAll(".avatar");
+ element.classList.add("catified");
+ element.classList.add(this.type);
+ const avatars = element.querySelectorAll(".Avatar");
for (const avatarIndex in avatars) {
const currentAvatar = avatars[avatarIndex];
if (currentAvatar.style) {
if (this.colors.borderColor === "#000000") {
this.detectColors(currentAvatar);
}
currentAvatar.style.backgroundColor = this.colors.backgroundColor;
currentAvatar.style.borderColor = this.colors.borderColor;
}
}
}
},
function nyaByPost (element) {
- if (element.querySelectorAll && this.config.nya.enabled) {
+ if (element.querySelectorAll && this.config.nya.enabled && element.classList.contains("cat")) {
const contents = element.querySelectorAll(".status-content");
for (const content of contents) {
if (content.innerHTML) {
const regex = new RegExp(this.config.nya.matcher, "g");
let match;
while ((match = regex.exec(content.innerHTML)) !== null) {
const source = match[0];
const dest = source.replace(
new RegExp(this.config.nya.replacer.source, "g"),
this.config.nya.replacer.dest
);
content.innerHTML = content.innerHTML.replace(source, dest);
}
}
}
}
},
function detectColors (avatarElement) {
const images = avatarElement.querySelectorAll("img");
for (const imageIndex in images) {
images[imageIndex].crossOrigin = "anonymous";
const colorAvatar = () => {
const detector = new ColorDetector(images[imageIndex]);
detector.detect().then((color) => {
this.colors.backgroundColor = detector.getHexColor();
this.colors.borderColor = detector.getHexColor({ r: -40, g: -40, b: -40 });
avatarElement.style.backgroundColor = this.colors.backgroundColor;
avatarElement.style.borderColor = this.colors.borderColor;
});
};
if (images[imageIndex].complete) {
colorAvatar();
} else {
images[imageIndex].onload = colorAvatar;
}
return;
}
}
].forEach((fn) => { PleromaCat.prototype[fn.name] = fn; });
function PleromaModCatify () {
- this.cats = {};
+ this.animals = {};
this.config = {
stylesheet: "style.css",
triggers: {
- displayName: [
- "🐱",
- "😺",
- "🐈",
- "😼",
- "😹",
- "にゃ",
- "cat",
- "mew",
- "meow",
- "nya",
- "miaou",
- "kitten",
- "kitn",
- "ktn",
- "kadse",
- "catte"
- ],
- instances: [
- "misskey.io"
- ]
+ cat: {
+ displayName: [
+ "🐱",
+ "😺",
+ "🐈",
+ "😼",
+ "😹",
+ "にゃ",
+ "cat",
+ "mew",
+ "meow",
+ "nya",
+ "miaou",
+ "kitten",
+ "kitn",
+ "ktn",
+ "kadse",
+ "catte"
+ ],
+ instances: [
+ "misskey.io"
+ ]
+ },
+ bear: {
+ displayName: [
+ "🐻"
+ ],
+ instances: []
+ },
+ rabbit: {
+ displayName: [
+ "🐰",
+ "🐇",
+ "rabbit",
+ "bunny",
+ "hase",
+ "häschen",
+ "kaninchen"
+ ],
+ instances: []
+ }
},
filter: [
"user-info",
"timeline",
+ "Conversation",
"panel-body",
"main",
"active",
"status-body"
]
};
this.loadConfig();
}
[
function loadConfig () {
window.fetch(PleromaModLoader.getModDir() + "pleroma-mod-catify/config.json").then((response) => {
if (response.ok) {
response.json().then((json) => {
PleromaModCatify.config = json;
- this.config.triggers.displayName = json.triggers.displayName;
- this.config.triggers.instances = json.triggers.instances;
+ for (const type in json.triggers) {
+ this.config.triggers[type] = {};
+ this.config.triggers[type].displayName = json.triggers[type].displayName || [];
+ this.config.triggers[type].instances = json.triggers[type].instances || [];
+ }
}).catch((error) => {
console.error("can't parse catify config");
console.error(error);
});
}
}).catch((error) => {
console.warn("can't load catify config");
console.warn(error);
});
},
function onMutation (mutation, observer) {
if (mutation.target.classList.contains("user-info")) {
- mutation.target.classList.remove("cat");
+ mutation.target.classList.remove("catified");
+ for (const type in this.config.triggers) {
+ mutation.target.classList.remove(type);
+ }
}
this.detectCats();
for (const element of mutation.addedNodes) {
this.catify(element);
}
},
function onReady () {
this.areYouACat();
this.detectCats();
this.catify();
},
function onDestroy () {
- const allCats = document.querySelectorAll(".cat");
+ const allCats = document.querySelectorAll(".catified");
for (const cat of allCats) {
- cat.classList.remove("cat");
+ cat.classList.remove("catified");
+ for (const type in this.config.triggers) {
+ cat.classList.remove(type);
+ }
}
},
function run () {
PleromaModLoader.includeModCss("pleroma-mod-catify/" + this.config.stylesheet);
},
- function addCat (handle) {
+ function addCat (handle, type) {
+ if (type == null) {
+ type = "cat";
+ }
handle = handle.trim();
- if (!this.cats.handle) {
- this.cats[handle] = new PleromaCat(handle);
+ if (!this.animals[handle]) {
+ this.animals[handle] = new PleromaCat(handle, type);
}
},
function areYouACat () {
const profile = document.querySelector(".user-card");
- const pattern = this.config.triggers.displayName.join("|");
- const regex = new RegExp(pattern, "i");
- if (profile) {
- const username = profile.querySelector(".user-name");
- if (username) {
- if (regex.test(username.innerText)) {
- const accountName = profile.querySelector(".user-screen-name");
- if (accountName) {
- this.addCat(accountName.innerText.substring(1), true);
+ for (const type in this.config.triggers) {
+ const pattern = this.config.triggers[type].displayName.join("|");
+ const regex = new RegExp(pattern, "i");
+ if (profile) {
+ const username = profile.querySelector(".user-name");
+ if (username) {
+ if (regex.test(username.innerText)) {
+ const accountName = profile.querySelector(".user-screen-name");
+ if (accountName) {
+ this.addCat(accountName.innerText.substring(1), type);
+ }
}
}
}
}
},
function detectCatsByClassName (classname, usernameClass, accountnameClass) {
- classname = classname || "name-and-account-name";
- usernameClass = usernameClass || "user-name";
+ classname = classname || "status-container";
+ usernameClass = usernameClass || "status-username";
accountnameClass = accountnameClass || "account-name";
const nameAndAccountNames = document.querySelectorAll("." + classname);
- const regexName = new RegExp(this.config.triggers.displayName.join("|"), "i");
- const regexInstance = new RegExp(this.config.triggers.instances.join("|"), "i");
- for (const currentAccount of nameAndAccountNames) {
- if (currentAccount.querySelector) {
- let isCat = false;
- const username = currentAccount.querySelector("." + usernameClass);
- if (username) {
- isCat = regexName.test(username.innerText);
- }
- const account = currentAccount.querySelector("." + accountnameClass);
- if (account) {
- const handle = account.innerText;
- isCat = isCat || regexInstance.test(handle);
- if (isCat) {
- this.addCat(handle);
+ for (const type in this.config.triggers) {
+ const regexName = new RegExp(this.config.triggers[type].displayName.join("|"), "i");
+ const regexInstance = new RegExp(this.config.triggers[type].instances.join("|"), "i");
+ for (const currentAccount of nameAndAccountNames) {
+ if (currentAccount.querySelector) {
+ let isCat = false;
+ const username = currentAccount.querySelector("." + usernameClass);
+ if (username && this.config.triggers[type].displayName.length > 0) {
+ isCat = regexName.test(username.innerText);
+ }
+ const account = currentAccount.querySelector("." + accountnameClass);
+ if (account) {
+ const handle = account.innerText;
+ if (this.config.triggers[type].instances.length > 0) {
+ isCat = isCat || regexInstance.test(handle);
+ }
+ if (isCat) {
+ this.addCat(handle, type);
+ }
}
}
}
}
},
function detectCats () {
- this.detectCatsByClassName("name-and-account-name");
+ this.detectCatsByClassName("status-container");
this.detectCatsByClassName("basic-user-card", "basic-user-card-user-name-value", "basic-user-card-screen-name");
},
function catify (element) {
- for (const catKey in this.cats) {
- this.cats[catKey].makeCat(element);
+ for (const catKey in this.animals) {
+ this.animals[catKey].makeCat(element);
}
}
].forEach((fn) => { PleromaModCatify.prototype[fn.name] = fn; });
PleromaModLoader.registerMod(PleromaModCatify);
diff --git a/instance/pleroma-mods/pleroma-mod-catify/style.css b/instance/pleroma-mods/pleroma-mod-catify/style.css
index 08ce64b72b..7cfea2f276 100644
--- a/instance/pleroma-mods/pleroma-mod-catify/style.css
+++ b/instance/pleroma-mods/pleroma-mod-catify/style.css
@@ -1,73 +1,123 @@
-.cat>:not(.status-body) .avatar::before, .cat>:not(.status-body) .avatar::after {
+.catified>:not(.status-container) .Avatar::before, .catified>:not(.status-container) .Avatar::after {
content: "";
display: inline-block;
border: 4px solid;
box-sizing: border-box;
width: 50%;
height: 50%;
background-color: inherit;
border-color: inherit;
position: absolute;
z-index: 0;
}
-.cat>:not(.status-body) .avatar {
+.catified>:not(.status-container) .Avatar {
overflow: visible;
border-radius: 100%!important;
}
-.cat .user-info-avatar-link-overlay {
+.catified .user-info-avatar-link-overlay {
border-radius: 100%!important;
z-index: 1;
}
-.cat>:not(.status-body) .avatar img, .cat>:not(.status-body) .avatar canvas {
+.catified>:not(.status-container) .Avatar img, .catified>:not(.status-container) .Avatar canvas {
border-radius: 100%;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1;
position: absolute;
}
-.cat>:not(.status-body) .avatar::before {
- border-radius: 75% 0 75% 75%;
+.catified>:not(.status-container) .Avatar::before {
transform: rotate(-37.6deg) skew(-30deg);
top: 0;
bottom: 0;
right: 0;
}
-.cat .avatar:hover::before {
+.catified.cat>:not(.status-container) .Avatar::before {
+ border-radius: 75% 0 75% 75%;
+}
+
+.catified.bear>:not(.status-container) .Avatar::before {
+ border-radius: 75%;
+ top: -3px;
+}
+
+.catified .Avatar:hover::before {
animation: earwiggleright 1s infinite;
}
-.cat>:not(.status-body) .avatar::after {
- border-radius: 0 75% 75%;
+.catified>:not(.status-container) .Avatar::after {
transform: rotate(37.6deg) skew(30deg);
top: 0;
bottom: 0;
left: 0;
right: 0;
}
-.cat .avatar:hover::after {
+.catified.cat>:not(.status-container) .Avatar::after {
+ border-radius: 0 75% 75%;
+}
+
+.catified.bear>:not(.status-container) .Avatar::after {
+ border-radius: 75%;
+ top: -3px;
+}
+
+.catified .Avatar:hover::after {
animation: earwiggleleft 1s infinite;
}
@keyframes earwiggleleft {
from { transform: rotate(37.6deg) skew(30deg); }
25% { transform: rotate(10deg) skew(30deg); }
50% { transform: rotate(20deg) skew(30deg); }
75% { transform: rotate(0deg) skew(30deg); }
to { transform: rotate(37.6deg) skew(30deg); }
}
@keyframes earwiggleright {
from { transform: rotate(-37.6deg) skew(-30deg); }
30% { transform: rotate(-10deg) skew(-30deg); }
55% { transform: rotate(-20deg) skew(-30deg); }
75% { transform: rotate(-0deg) skew(-30deg); }
to { transform: rotate(-37.6deg) skew(-30deg); }
}
+
+.catified.rabbit>:not(.status-container) .Avatar::before,
+.catified.rabbit>:not(.status-container) .Avatar::after {
+ /* 100px makes that it's actually just rounding and not a curve between the top and the sides */
+ border-radius: 100px 100px 0 0;
+ border-width: 3px;
+ height: 100%;
+}
+.catified.rabbit>:not(.status-container) .Avatar::before {
+ transform: rotate(10deg);
+ top: -.5rem;
+ right: 13.25%;
+ width: 18.5%;
+}
+.catified.rabbit>:not(.status-container) .Avatar::after {
+ transform: none;
+ top: -.7rem;
+ left: 13.25%;
+ width: 20%;
+}
+.catified.rabbit .Avatar:hover::before { animation: earwiggleright-rabbit 0.65s infinite; }
+.catified.rabbit .Avatar:hover::after { animation: earwiggleleft-rabbit 0.65s infinite; }
+
+@keyframes earwiggleleft-rabbit {
+ from { transform: rotate(0deg); }
+ 75% { transform: rotate(-25deg); }
+ to { transform: rotate(0deg); }
+}
+
+@keyframes earwiggleright-rabbit {
+ from { transform: rotate(10deg); }
+ 75% { transform: rotate(25deg); }
+ to { transform: rotate(10deg); }
+}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 10, 7:34 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785106
Default Alt Text
(21 KB)

Event Timeline