Feat:ゴリラモード

This commit is contained in:
mattyatea 2023-11-02 16:51:03 +09:00
parent 10d38335f2
commit 5335e68bde
13 changed files with 108 additions and 8 deletions

2
locales/index.d.ts vendored
View file

@ -175,7 +175,9 @@ export interface Locale {
"flagAsBot": string; "flagAsBot": string;
"flagAsBotDescription": string; "flagAsBotDescription": string;
"flagAsCat": string; "flagAsCat": string;
"flagAsGorilla": string;
"flagAsCatDescription": string; "flagAsCatDescription": string;
"flagAsGorillaDescription": string;
"flagShowTimelineReplies": string; "flagShowTimelineReplies": string;
"showMediaTimeline": string; "showMediaTimeline": string;
"showMediaTimelineInfo": string; "showMediaTimelineInfo": string;

View file

@ -172,7 +172,9 @@ cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リ
flagAsBot: "Botとして設定" flagAsBot: "Botとして設定"
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。" flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!" flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
flagAsGorilla: "ウホウホウホホウホウホウホウホホホ!!!!!!!!!!!"
flagAsCatDescription: "にゃにゃにゃ??" flagAsCatDescription: "にゃにゃにゃ??"
flagAsGorillaDescription: "ウホウホウホ??"
flagShowTimelineReplies: "タイムラインにノートへの返信を表示する" flagShowTimelineReplies: "タイムラインにノートへの返信を表示する"
showMediaTimeline: "メディアタイムラインを表示する" showMediaTimeline: "メディアタイムラインを表示する"
showMediaTimelineInfo: "オンにするとメディアタイムラインを上のバーに表示します。 オフにすると表示しなくなります。" showMediaTimelineInfo: "オンにするとメディアタイムラインを上のバーに表示します。 オフにすると表示しなくなります。"

View file

@ -224,6 +224,7 @@ export class NoteCreateService implements OnApplicationShutdown {
host: MiUser['host']; host: MiUser['host'];
isBot: MiUser['isBot']; isBot: MiUser['isBot'];
isCat: MiUser['isCat']; isCat: MiUser['isCat'];
isGorilla: MiUser['isGorilla'];
}, data: Option, silent = false): Promise<MiNote> { }, data: Option, silent = false): Promise<MiNote> {
// チャンネル外にリプライしたら対象のスコープに合わせる // チャンネル外にリプライしたら対象のスコープに合わせる
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)

View file

@ -366,6 +366,7 @@ export class UserEntityService implements OnModuleInit {
}))) : [], }))) : [],
isBot: user.isBot, isBot: user.isBot,
isCat: user.isCat, isCat: user.isCat,
isGorilla: user.isGorilla,
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
name: instance.name, name: instance.name,
softwareName: instance.softwareName, softwareName: instance.softwareName,

View file

@ -177,6 +177,12 @@ export class MiUser {
}) })
public isCat: boolean; public isCat: boolean;
@Column('boolean', {
default: false,
comment: 'Whether the User is a gorilla.',
})
public isGorilla: boolean;
@Column('boolean', { @Column('boolean', {
default: false, default: false,
comment: 'Whether the User is the root.', comment: 'Whether the User is the root.',

View file

@ -83,6 +83,10 @@ export const packedUserLiteSchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: true, nullable: false, optional: true,
}, },
isGorilla: {
type: 'boolean',
nullable: false, optional: true,
},
onlineStatus: { onlineStatus: {
type: 'string', type: 'string',
format: 'url', format: 'url',

View file

@ -165,6 +165,7 @@ export const paramDef = {
preventAiLearning: { type: 'boolean' }, preventAiLearning: { type: 'boolean' },
isBot: { type: 'boolean' }, isBot: { type: 'boolean' },
isCat: { type: 'boolean' }, isCat: { type: 'boolean' },
isGorilla: { type: 'boolean' },
injectFeaturedNote: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' },
receiveAnnouncementEmail: { type: 'boolean' }, receiveAnnouncementEmail: { type: 'boolean' },
alwaysMarkNsfw: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' },
@ -267,7 +268,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning; if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; if (typeof ps.isCat === 'boolean' && !ps.isGorilla) {
updates.isCat = ps.isCat;
};
if (typeof ps.isGorilla === 'boolean' && !ps.isCat) {
updates.isGorilla = ps.isGorilla
};
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
if (typeof ps.alwaysMarkNsfw === 'boolean') { if (typeof ps.alwaysMarkNsfw === 'boolean') {

View file

@ -16,6 +16,8 @@ import { defaultStore } from '@/store';
import { mixEmoji } from '@/scripts/emojiKitchen/emojiMixer'; import { mixEmoji } from '@/scripts/emojiKitchen/emojiMixer';
import MkRuby from "@/components/global/MkRuby.vue"; import MkRuby from "@/components/global/MkRuby.vue";
import { nyaize as doNyaize } from '@/scripts/nyaize.js'; import { nyaize as doNyaize } from '@/scripts/nyaize.js';
import { uhoize as doUhoize } from '@/scripts/uhoize.js';
import {ID, Instance} from "misskey-js/built/entities.js";
const QUOTE_STYLE = ` const QUOTE_STYLE = `
display: block; display: block;
@ -62,12 +64,41 @@ type MfmProps = {
text: string; text: string;
plain?: boolean; plain?: boolean;
nowrap?: boolean; nowrap?: boolean;
author?: Misskey.entities.UserLite; author?: {
id: ID;
username: string;
host: string | null;
name: string | null;
onlineStatus: 'online' | 'active' | 'offline' | 'unknown';
avatarUrl: string;
avatarBlurhash: string;
avatarDecorations: {
id: ID;
url: string;
angle?: number;
flipH?: boolean;
}[];
emojis: {
name: string;
url: string;
}[];
instance?: {
name: Instance['name'];
softwareName: Instance['softwareName'];
softwareVersion: Instance['softwareVersion'];
iconUrl: Instance['iconUrl'];
faviconUrl: Instance['faviconUrl'];
themeColor: Instance['themeColor'];
};
isGorilla?: boolean;
isCat?: boolean;
isBot?: boolean;};
i?: Misskey.entities.UserLite | null; i?: Misskey.entities.UserLite | null;
isNote?: boolean; isNote?: boolean;
emojiUrls?: string[]; emojiUrls?: string[];
rootScale?: number; rootScale?: number;
nyaize: boolean | 'account'; nyaize: boolean | 'account';
uhoize: boolean | 'account';
parsedNodes?: mfm.MfmNode[] | null; parsedNodes?: mfm.MfmNode[] | null;
}; };
@ -75,7 +106,8 @@ type MfmProps = {
export default function(props: MfmProps) { export default function(props: MfmProps) {
const isNote = props.isNote ?? true; const isNote = props.isNote ?? true;
const shouldNyaize = props.nyaize ? props.nyaize === 'account' ? props.author?.isCat : false : false; const shouldNyaize = props.nyaize ? props.nyaize === 'account' ? props.author?.isCat : false : false;
const shouldUhoize = props.nyaize ? props.nyaize === 'account' ? props.author?.isGorilla : false : false;
console.log(shouldUhoize, props.nyaize,props.author?.isGorilla)
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (props.text == null || props.text === '') return; if (props.text == null || props.text === '') return;
@ -93,15 +125,18 @@ export default function(props: MfmProps) {
* @param ast MFM AST * @param ast MFM AST
* @param scale How times large the text is * @param scale How times large the text is
* @param disableNyaize Whether nyaize is disabled or not * @param disableNyaize Whether nyaize is disabled or not
* @param disableUhoize
*/ */
const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false) => ast.map((token): VNode | string | (VNode | string)[] => { const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false, disableUhoize = false) => ast.map((token): VNode | string | (VNode | string)[] => {
switch (token.type) { switch (token.type) {
case 'text': { case 'text': {
let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (!disableNyaize && shouldNyaize) { if (!disableNyaize && shouldNyaize) {
text = doNyaize(text); text = doNyaize(text);
} }
if (!disableUhoize && shouldUhoize) {
text = doUhoize(text);
}
if (!props.plain) { if (!props.plain) {
const res: (VNode | string)[] = []; const res: (VNode | string)[] = [];
for (const t of text.split('\n')) { for (const t of text.split('\n')) {

View file

@ -105,7 +105,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.advancedSettings }}</template> <template #label>{{ i18n.ts.advancedSettings }}</template>
<div class="_gaps_m"> <div class="_gaps_m">
<MkSwitch v-model="profile.isCat">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></MkSwitch> <MkSwitch :disabled="profile.isGorilla" v-model="profile.isCat">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></MkSwitch>
<MkSwitch :disabled="profile.isCat" v-model="profile.isGorilla">{{ i18n.ts.flagAsGorilla }}<template #caption>{{ i18n.ts.flagAsGorillaDescription }}</template></MkSwitch>
<MkSwitch v-model="profile.isBot">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></MkSwitch> <MkSwitch v-model="profile.isBot">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></MkSwitch>
</div> </div>
</MkFolder> </MkFolder>
@ -154,6 +155,7 @@ const profile = reactive({
lang: $i.lang, lang: $i.lang,
isBot: $i.isBot, isBot: $i.isBot,
isCat: $i.isCat, isCat: $i.isCat,
isGorilla: $i.isGorilla,
}); });
watch(() => profile, () => { watch(() => profile, () => {
@ -206,6 +208,7 @@ function save() {
lang: profile.lang || null, lang: profile.lang || null,
isBot: !!profile.isBot, isBot: !!profile.isBot,
isCat: !!profile.isCat, isCat: !!profile.isCat,
isGorilla: !!profile.isGorilla,
}); });
claimAchievement('profileFilled'); claimAchievement('profileFilled');
if (profile.name === 'syuilo' || profile.name === 'しゅいろ') { if (profile.name === 'syuilo' || profile.name === 'しゅいろ') {
@ -214,6 +217,9 @@ function save() {
if (profile.isCat) { if (profile.isCat) {
claimAchievement('markedAsCat'); claimAchievement('markedAsCat');
} }
if (profile.isGorilla) {
claimAchievement('markedAsCat');
}
} }
function changeAvatar(ev) { function changeAvatar(ev) {

View file

@ -265,6 +265,11 @@ export const ACHIEVEMENT_BADGES = {
bg: 'linear-gradient(0deg, rgb(187 183 59), rgb(255 143 77))', bg: 'linear-gradient(0deg, rgb(187 183 59), rgb(255 143 77))',
frame: 'bronze', frame: 'bronze',
}, },
'markedAsGorilla': {
img: '/fluent-emoji/1f98D.png',
bg: 'linear-gradient(0deg, rgba(55,0,0,1) 0%, rgba(107,5,5,1) 59%, rgba(158,6,6,1) 100%)',
frame: 'bronze',
},
'following1': { 'following1': {
img: '/fluent-emoji/2618.png', img: '/fluent-emoji/2618.png',
bg: 'linear-gradient(0deg, rgb(59 187 116), rgb(199 211 102))', bg: 'linear-gradient(0deg, rgb(59 187 116), rgb(199 211 102))',

View file

@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export function uhoize(text) {
const gorillaNoises = ['ウホ', 'ウホホ', 'ウホッ'];
let result = '';
let noiseIndex = 0;
for (let i = 0; i < text.length; i++) {
if (!(/[、。.,\/#!$%\^&\*;:{}=\-_`~()]/.test(text[i]))) {
if (/[^\x00-\x7F]/.test(text[i])) {
noiseIndex = Math.floor(Math.random() * 3);
const japaneseNoises = ['ウホ', 'ウホホ', 'ウホッ'];
result += japaneseNoises[noiseIndex];
} else {
noiseIndex = Math.floor(Math.random() * 2);
const englishNoises = ['uho', 'uhoho'];
result += englishNoises[noiseIndex];
}
}else{
result += text[i];
}
if (text.length*1.3 < result.length) return result
}
return result;
}

View file

@ -2951,6 +2951,7 @@ type UserDetailed = UserLite & {
isBlocking: boolean; isBlocking: boolean;
isBot: boolean; isBot: boolean;
isCat: boolean; isCat: boolean;
isGorilla: boolean;
isFollowed: boolean; isFollowed: boolean;
isFollowing: boolean; isFollowing: boolean;
isLocked: boolean; isLocked: boolean;
@ -3014,6 +3015,7 @@ type UserLite = {
faviconUrl: Instance['faviconUrl']; faviconUrl: Instance['faviconUrl'];
themeColor: Instance['themeColor']; themeColor: Instance['themeColor'];
}; };
isGorilla?: boolean;
isCat?: boolean; isCat?: boolean;
isBot?: boolean; isBot?: boolean;
}; };
@ -3026,8 +3028,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
// src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:118:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
// src/entities.ts:614:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/entities.ts:616:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
// (No @packageDocumentation comment for this package) // (No @packageDocumentation comment for this package)

View file

@ -34,6 +34,7 @@ export type UserLite = {
faviconUrl: Instance['faviconUrl']; faviconUrl: Instance['faviconUrl'];
themeColor: Instance['themeColor']; themeColor: Instance['themeColor'];
}; };
isGorilla?: boolean;
isCat?: boolean; isCat?: boolean;
isBot?: boolean; isBot?: boolean;
}; };
@ -58,6 +59,7 @@ export type UserDetailed = UserLite & {
isBlocking: boolean; isBlocking: boolean;
isBot: boolean; isBot: boolean;
isCat: boolean; isCat: boolean;
isGorilla: boolean;
isFollowed: boolean; isFollowed: boolean;
isFollowing: boolean; isFollowing: boolean;
isLocked: boolean; isLocked: boolean;