Merge pull request MisskeyIO#246 from MisskeyIO/merge-upstream
Merge misskey-dev/develop
This commit is contained in:
@@ -70,7 +70,7 @@
|
||||
"tsc-alias": "1.8.8",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typescript": "5.2.2",
|
||||
"typescript": "5.3.2",
|
||||
"uuid": "9.0.1",
|
||||
"v-code-diff": "1.7.2",
|
||||
"vanilla-tilt": "1.8.1",
|
||||
|
@@ -114,7 +114,6 @@ const props = defineProps<{
|
||||
|
||||
& + article {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +123,7 @@ const props = defineProps<{
|
||||
|
||||
> .thumbnail {
|
||||
height: 80px;
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
> article {
|
||||
|
@@ -123,12 +123,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
</MkFolder>
|
||||
|
||||
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
|
||||
|
||||
<div>
|
||||
<MkButton v-if="iAmModerator" inline danger style="margin-right: 8px;" @click="deleteUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.deleteUserAvatar }}</MkButton>
|
||||
<MkButton v-if="iAmModerator" inline danger @click="deleteUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.deleteUserBanner }}</MkButton>
|
||||
<MkButton v-if="iAmModerator" inline danger style="margin-right: 8px;" @click="unsetUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.unsetUserAvatar }}</MkButton>
|
||||
<MkButton v-if="iAmModerator" inline danger @click="unsetUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.unsetUserBanner }}</MkButton>
|
||||
</div>
|
||||
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
@@ -330,14 +329,14 @@ async function toggleSuspend(v) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteUserAvatar() {
|
||||
async function unsetUserAvatar() {
|
||||
const confirm = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.ts.deleteUserAvatarConfirm,
|
||||
text: i18n.ts.unsetUserAvatarConfirm,
|
||||
});
|
||||
if (confirm.canceled) return;
|
||||
const process = async () => {
|
||||
await os.api('admin/delete-user-avatar', { userId: user.id });
|
||||
await os.api('admin/unset-user-avatar', { userId: user.id });
|
||||
os.success();
|
||||
};
|
||||
await process().catch(err => {
|
||||
@@ -349,14 +348,14 @@ async function deleteUserAvatar() {
|
||||
refreshUser();
|
||||
}
|
||||
|
||||
async function deleteUserBanner() {
|
||||
async function unsetUserBanner() {
|
||||
const confirm = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.ts.deleteUserBannerConfirm,
|
||||
text: i18n.ts.unsetUserBannerConfirm,
|
||||
});
|
||||
if (confirm.canceled) return;
|
||||
const process = async () => {
|
||||
await os.api('admin/delete-user-banner', { userId: user.id });
|
||||
await os.api('admin/unset-user-banner', { userId: user.id });
|
||||
os.success();
|
||||
};
|
||||
await process().catch(err => {
|
||||
|
@@ -38,6 +38,7 @@ import { } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
@@ -73,6 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save">
|
||||
<template #label>Enable</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="enableVerifymailApi" @update:modelValue="save">
|
||||
<template #label>Use Verifymail API</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="verifymailAuthKey" @update:modelValue="save">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Verifymail API Auth Key</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
@@ -132,6 +139,8 @@ let setSensitiveFlagAutomatically: boolean = $ref(false);
|
||||
let enableSensitiveMediaDetectionForVideos: boolean = $ref(false);
|
||||
let enableIpLogging: boolean = $ref(false);
|
||||
let enableActiveEmailValidation: boolean = $ref(false);
|
||||
let enableVerifymailApi: boolean = $ref(false);
|
||||
let verifymailAuthKey: string | null = $ref(null);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
@@ -150,6 +159,8 @@ async function init() {
|
||||
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
|
||||
enableIpLogging = meta.enableIpLogging;
|
||||
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
||||
enableVerifymailApi = meta.enableVerifymailApi;
|
||||
verifymailAuthKey = meta.verifymailAuthKey;
|
||||
}
|
||||
|
||||
function save() {
|
||||
@@ -167,6 +178,8 @@ function save() {
|
||||
enableSensitiveMediaDetectionForVideos,
|
||||
enableIpLogging,
|
||||
enableActiveEmailValidation,
|
||||
enableVerifymailApi,
|
||||
verifymailAuthKey,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
|
@@ -54,22 +54,24 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||
const { t, ts } = i18n;
|
||||
|
||||
const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||
'collapseRenotes',
|
||||
'menu',
|
||||
'visibility',
|
||||
'localOnly',
|
||||
'statusbars',
|
||||
'widgets',
|
||||
'tl',
|
||||
'pinnedUserLists',
|
||||
'overridedDeviceKind',
|
||||
'serverDisconnectedBehavior',
|
||||
'collapseRenotes',
|
||||
'showNoteActionsOnlyHover',
|
||||
'nsfw',
|
||||
'highlightSensitiveMedia',
|
||||
'animation',
|
||||
'animatedMfm',
|
||||
'advancedMfm',
|
||||
'loadRawImages',
|
||||
'imageNewTab',
|
||||
'enableDataSaverMode',
|
||||
'disableShowingAnimatedImages',
|
||||
'emojiStyle',
|
||||
'disableDrawer',
|
||||
@@ -89,9 +91,28 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||
'menuDisplay',
|
||||
'reportError',
|
||||
'squareAvatars',
|
||||
'showAvatarDecorations',
|
||||
'numberOfPageCache',
|
||||
'showNoteActionsOnlyHover',
|
||||
'showClipButtonInNoteFooter',
|
||||
'reactionsDisplaySize',
|
||||
'forceShowAds',
|
||||
'aiChanMode',
|
||||
'devMode',
|
||||
'mediaListWithOneImageAppearance',
|
||||
'notificationPosition',
|
||||
'notificationStackAxis',
|
||||
'enableCondensedLineForAcct',
|
||||
'keepScreenOn',
|
||||
'defaultWithReplies',
|
||||
'disableStreamingTimeline',
|
||||
'useGroupedNotifications',
|
||||
'sound_masterVolume',
|
||||
'sound_note',
|
||||
'sound_noteMy',
|
||||
'sound_notification',
|
||||
'sound_antenna',
|
||||
'sound_channel',
|
||||
];
|
||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||
'lightTheme',
|
||||
|
@@ -122,7 +122,7 @@ export const soundsTypes = [
|
||||
'Copyright_Misskey.io/ThinaticSystem/yonderuzo3',
|
||||
] as const;
|
||||
|
||||
export async function getAudio(file: string, useCache = true) {
|
||||
export async function loadAudio(file: string, useCache = true) {
|
||||
if (useCache && cache.has(file)) {
|
||||
return cache.get(file)!;
|
||||
}
|
||||
@@ -138,12 +138,6 @@ export async function getAudio(file: string, useCache = true) {
|
||||
return audioBuffer;
|
||||
}
|
||||
|
||||
export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement {
|
||||
const masterVolume = defaultStore.state.sound_masterVolume;
|
||||
audio.volume = masterVolume - ((1 - volume) * masterVolume);
|
||||
return audio;
|
||||
}
|
||||
|
||||
export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification') {
|
||||
const sound = defaultStore.state[`sound_${type}`];
|
||||
if (_DEV_) console.log('play', type, sound);
|
||||
@@ -152,16 +146,22 @@ export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notifica
|
||||
}
|
||||
|
||||
export async function playFile(file: string, volume: number) {
|
||||
const buffer = await loadAudio(file);
|
||||
createSourceNode(buffer, volume)?.start();
|
||||
}
|
||||
|
||||
export function createSourceNode(buffer: AudioBuffer, volume: number) : AudioBufferSourceNode | null {
|
||||
const masterVolume = defaultStore.state.sound_masterVolume;
|
||||
if (masterVolume === 0 || volume === 0) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
const gainNode = ctx.createGain();
|
||||
gainNode.gain.value = masterVolume * volume;
|
||||
|
||||
const soundSource = ctx.createBufferSource();
|
||||
soundSource.buffer = await getAudio(file);
|
||||
soundSource.buffer = buffer;
|
||||
soundSource.connect(gainNode).connect(ctx.destination);
|
||||
soundSource.start();
|
||||
|
||||
return soundSource;
|
||||
}
|
||||
|
@@ -99,7 +99,10 @@ const current = reactive({
|
||||
},
|
||||
});
|
||||
const prev = reactive({} as typeof current);
|
||||
const jammedSound = sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1);
|
||||
let jammedAudioBuffer: AudioBuffer | null = $ref(null);
|
||||
let jammedSoundNodePlaying: boolean = $ref(false);
|
||||
|
||||
sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf);
|
||||
|
||||
for (const domain of ['inbox', 'deliver']) {
|
||||
prev[domain] = deepClone(current[domain]);
|
||||
@@ -113,8 +116,13 @@ const onStats = (stats) => {
|
||||
current[domain].waiting = stats[domain].waiting;
|
||||
current[domain].delayed = stats[domain].delayed;
|
||||
|
||||
if (current[domain].waiting > 0 && widgetProps.sound && jammedSound.paused) {
|
||||
jammedSound.play();
|
||||
if (current[domain].waiting > 0 && widgetProps.sound && jammedAudioBuffer && !jammedSoundNodePlaying) {
|
||||
const soundNode = sound.createSourceNode(jammedAudioBuffer, 1);
|
||||
if (soundNode) {
|
||||
jammedSoundNodePlaying = true;
|
||||
soundNode.onended = () => jammedSoundNodePlaying = false;
|
||||
soundNode.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user