diff --git a/CHANGELOG.md b/CHANGELOG.md index 4def7e5f88..bc0b3b5c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ --> +## 12.101.1 (2021/12/29) + +### Bugfixes +- SVG絵文字が表示できないのを修正 +- エクスポートした絵文字の拡張子がfalseになることがあるのを修正 + ## 12.101.0 (2021/12/29) ### Improvements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 633995c947..a16a76abcf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,7 @@ Configuration files are located in [`/.github/workflows`](/.github/workflows). ## Vue Misskey uses Vue(v3) as its front-end framework. -**When creating a new component, please use the Composition API (and [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html)) instead of the Options API.** +**When creating a new component, please use the Composition API (with [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html) and [ref sugar](https://github.com/vuejs/rfcs/discussions/369)) instead of the Options API.** Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome. ## Adding MisskeyRoom items diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d326099359..b77a54bbf0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -743,7 +743,7 @@ online: "オンライン" active: "アクティブ" offline: "オフライン" notRecommended: "非推奨" -botProtection: "Bot防御" +botProtection: "Botプロテクション" instanceBlocking: "インスタンスブロック" selectAccount: "アカウントを選択" enabled: "有効" @@ -754,7 +754,7 @@ administration: "管理" accounts: "アカウント" switch: "切り替え" noMaintainerInformationWarning: "管理者情報が設定されていません。" -noBotProtectionWarning: "Bot防御が設定されていません。" +noBotProtectionWarning: "Botプロテクションが設定されていません。" configure: "設定する" postToGallery: "ギャラリーへ投稿" gallery: "ギャラリー" diff --git a/package.json b/package.json index 0c5becdede..c42b71582b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.101.0", + "version": "12.101.1", "codename": "indigo", "repository": { "type": "git", diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts index 925b187970..3930b9d6d4 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -65,7 +65,8 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi for (const emoji of customEmojis) { const exportId = ulid().toLowerCase(); - const emojiPath = path + '/' + exportId + '.' + mime.extension(emoji.type); + const ext = mime.extension(emoji.type); + const emojiPath = path + '/' + exportId + (ext ? '.' + ext : ''); fs.writeFileSync(emojiPath, '', 'binary'); let downloaded = false; diff --git a/packages/backend/src/server/proxy/proxy-media.ts b/packages/backend/src/server/proxy/proxy-media.ts index b116b4b961..aba08bb805 100644 --- a/packages/backend/src/server/proxy/proxy-media.ts +++ b/packages/backend/src/server/proxy/proxy-media.ts @@ -19,6 +19,7 @@ export async function proxyMedia(ctx: Koa.Context) { const { mime, ext } = await detectType(path); + if (!mime.startsWith('image/')) throw 403; if (!FILE_TYPE_BROWSERSAFE.includes(mime)) throw 403; let image: IImage; diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index a59c9501bc..3d53fe8d34 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -161,7 +161,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } } - if (!['image/jpeg', 'image/png', 'image/webp'].includes(type)) { + if (!['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'].includes(type)) { logger.debug(`web image and thumbnail not created (not an required file)`); return { webpublic: null, @@ -202,7 +202,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool webpublic = await convertSharpToJpeg(img, 2048, 2048); } else if (['image/webp'].includes(type)) { webpublic = await convertSharpToWebp(img, 2048, 2048); - } else if (['image/png'].includes(type)) { + } else if (['image/png', 'image/svg+xml'].includes(type)) { webpublic = await convertSharpToPng(img, 2048, 2048); } else { logger.debug(`web image not created (not an required image)`); @@ -221,7 +221,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool try { if (['image/jpeg', 'image/webp'].includes(type)) { thumbnail = await convertSharpToJpeg(img, 498, 280); - } else if (['image/png'].includes(type)) { + } else if (['image/png', 'image/svg+xml'].includes(type)) { thumbnail = await convertSharpToPngOrJpeg(img, 498, 280); } else { logger.debug(`thumbnail not created (not an required file)`); diff --git a/packages/client/@types/vue.d.ts b/packages/client/@types/vue.d.ts index 8cb6130629..f6b66228f6 100644 --- a/packages/client/@types/vue.d.ts +++ b/packages/client/@types/vue.d.ts @@ -1,3 +1,5 @@ +/// + declare module '*.vue' { import type { DefineComponent } from 'vue'; const component: DefineComponent<{}, {}, any>; diff --git a/packages/client/package.json b/packages/client/package.json index 198bcbcef6..fe149890dd 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -116,7 +116,7 @@ "v-debounce": "0.1.2", "vanilla-tilt": "1.7.2", "vue": "3.2.26", - "vue-loader": "16.8.3", + "vue-loader": "17.0.0", "vue-prism-editor": "2.0.0-alpha.2", "vue-router": "4.0.5", "vue-style-loader": "4.1.3", diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index 46bcd42558..f8d3d810b7 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -53,6 +53,7 @@ import XFolder from './drive.folder.vue'; import XFile from './drive.file.vue'; import MkButton from './ui/button.vue'; import * as os from '@/os'; +import { stream } from '@/stream'; export default defineComponent({ components: { @@ -140,7 +141,7 @@ export default defineComponent({ }); } - this.connection = markRaw(os.stream.useChannel('drive')); + this.connection = markRaw(stream.useChannel('drive')); this.connection.on('fileCreated', this.onStreamDriveFileCreated); this.connection.on('fileUpdated', this.onStreamDriveFileUpdated); diff --git a/packages/client/src/components/follow-button.vue b/packages/client/src/components/follow-button.vue index 7136261914..b16b22f26f 100644 --- a/packages/client/src/components/follow-button.vue +++ b/packages/client/src/components/follow-button.vue @@ -30,6 +30,7 @@ diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue index aa9b09215e..ac3284e7da 100644 --- a/packages/client/src/components/form/switch.vue +++ b/packages/client/src/components/form/switch.vue @@ -13,7 +13,8 @@ - + +

diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue index 55a02f1e73..a5cb2f0426 100644 --- a/packages/client/src/components/note-detailed.vue +++ b/packages/client/src/components/note-detailed.vue @@ -140,6 +140,7 @@ import { checkWordMute } from '@/scripts/check-word-mute'; import { userPage } from '@/filters/user'; import { notePage } from '@/filters/note'; import * as os from '@/os'; +import { stream } from '@/stream'; import { noteActions, noteViewInterruptors } from '@/store'; import { reactionPicker } from '@/scripts/reaction-picker'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm'; @@ -260,7 +261,7 @@ export default defineComponent({ async created() { if (this.$i) { - this.connection = os.stream; + this.connection = stream; } this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords); diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index c4040388a9..3cf924928a 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -122,6 +122,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard'; import { checkWordMute } from '@/scripts/check-word-mute'; import { userPage } from '@/filters/user'; import * as os from '@/os'; +import { stream } from '@/stream'; import { noteActions, noteViewInterruptors } from '@/store'; import { reactionPicker } from '@/scripts/reaction-picker'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm'; @@ -245,7 +246,7 @@ export default defineComponent({ async created() { if (this.$i) { - this.connection = os.stream; + this.connection = stream; } this.collapsed = this.appearNote.cw == null && this.appearNote.text && ( diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue index 0e9fcbf1df..eda702085b 100644 --- a/packages/client/src/components/notification.vue +++ b/packages/client/src/components/notification.vue @@ -74,6 +74,7 @@ import { notePage } from '@/filters/note'; import { userPage } from '@/filters/user'; import { i18n } from '@/i18n'; import * as os from '@/os'; +import { stream } from '@/stream'; import { useTooltip } from '@/scripts/use-tooltip'; export default defineComponent({ @@ -106,7 +107,7 @@ export default defineComponent({ if (!props.notification.isRead) { const readObserver = new IntersectionObserver((entries, observer) => { if (!entries.some(entry => entry.isIntersecting)) return; - os.stream.send('readNotification', { + stream.send('readNotification', { id: props.notification.id }); observer.disconnect(); @@ -114,7 +115,7 @@ export default defineComponent({ readObserver.observe(elRef.value); - const connection = os.stream.useChannel('main'); + const connection = stream.useChannel('main'); connection.on('readAllNotifications', () => readObserver.disconnect()); watch(props.notification.isRead, () => { diff --git a/packages/client/src/components/notifications.vue b/packages/client/src/components/notifications.vue index b4960359fd..3d091c5f15 100644 --- a/packages/client/src/components/notifications.vue +++ b/packages/client/src/components/notifications.vue @@ -28,6 +28,7 @@ import XList from './date-separated-list.vue'; import XNote from './note.vue'; import { notificationTypes } from 'misskey-js'; import * as os from '@/os'; +import { stream } from '@/stream'; import MkButton from '@/components/ui/button.vue'; export default defineComponent({ @@ -100,7 +101,7 @@ export default defineComponent({ }, mounted() { - this.connection = markRaw(os.stream.useChannel('main')); + this.connection = markRaw(stream.useChannel('main')); this.connection.on('notification', this.onNotification); this.connection.on('readAllNotifications', () => { @@ -133,7 +134,7 @@ export default defineComponent({ onNotification(notification) { const isMuted = !this.allIncludeTypes.includes(notification.type); if (isMuted || document.visibilityState === 'visible') { - os.stream.send('readNotification', { + stream.send('readNotification', { id: notification.id }); } diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue index 4265c575e2..24f35da2e9 100644 --- a/packages/client/src/components/post-form.vue +++ b/packages/client/src/components/post-form.vue @@ -74,11 +74,11 @@ import { formatTimeString } from '@/scripts/format-time-string'; import { Autocomplete } from '@/scripts/autocomplete'; import { noteVisibilities } from 'misskey-js'; import * as os from '@/os'; +import { stream } from '@/stream'; import { selectFiles } from '@/scripts/select-file'; import { defaultStore, notePostInterruptors, postFormActions } from '@/store'; import { throttle } from 'throttle-debounce'; import MkInfo from '@/components/ui/info.vue'; -import { defaultStore } from '@/store'; export default defineComponent({ components: { @@ -176,7 +176,7 @@ export default defineComponent({ imeText: '', typing: throttle(3000, () => { if (this.channel) { - os.stream.send('typingOnChannel', { channel: this.channel.id }); + stream.send('typingOnChannel', { channel: this.channel.id }); } }), postFormActions, diff --git a/packages/client/src/components/taskmanager.vue b/packages/client/src/components/taskmanager.vue index 6901d88c2c..c5d2c6d8f8 100644 --- a/packages/client/src/components/taskmanager.vue +++ b/packages/client/src/components/taskmanager.vue @@ -83,6 +83,7 @@ import MkTab from '@/components/tab.vue'; import MkButton from '@/components/ui/button.vue'; import follow from '@/directives/follow-append'; import * as os from '@/os'; +import { stream } from '@/stream'; export default defineComponent({ components: { @@ -104,15 +105,15 @@ export default defineComponent({ const connections = shallowRef([]); const pools = shallowRef([]); const refreshStreamInfo = () => { - console.log(os.stream.sharedConnectionPools, os.stream.sharedConnections, os.stream.nonSharedConnections); - const conn = os.stream.sharedConnections.map(c => ({ + console.log(stream.sharedConnectionPools, stream.sharedConnections, stream.nonSharedConnections); + const conn = stream.sharedConnections.map(c => ({ id: c.id, name: c.name, channel: c.channel, users: c.pool.users, in: c.inCount, out: c.outCount, - })).concat(os.stream.nonSharedConnections.map(c => ({ + })).concat(stream.nonSharedConnections.map(c => ({ id: c.id, name: c.name, channel: c.channel, users: null, in: c.inCount, out: c.outCount, }))); conn.sort((a, b) => (a.id > b.id) ? 1 : -1); connections.value = conn; - pools.value = os.stream.sharedConnectionPools; + pools.value = stream.sharedConnectionPools; }; const interval = setInterval(refreshStreamInfo, 1000); onBeforeUnmount(() => { diff --git a/packages/client/src/components/timeline.vue b/packages/client/src/components/timeline.vue index f8a800872f..53697671b2 100644 --- a/packages/client/src/components/timeline.vue +++ b/packages/client/src/components/timeline.vue @@ -6,6 +6,7 @@ import { defineComponent, markRaw } from 'vue'; import XNotes from './notes.vue'; import * as os from '@/os'; +import { stream } from '@/stream'; import * as sound from '@/scripts/sound'; export default defineComponent({ @@ -92,33 +93,33 @@ export default defineComponent({ this.query = { antennaId: this.antenna }; - this.connection = markRaw(os.stream.useChannel('antenna', { + this.connection = markRaw(stream.useChannel('antenna', { antennaId: this.antenna })); this.connection.on('note', prepend); } else if (this.src == 'home') { endpoint = 'notes/timeline'; - this.connection = markRaw(os.stream.useChannel('homeTimeline')); + this.connection = markRaw(stream.useChannel('homeTimeline')); this.connection.on('note', prepend); - this.connection2 = markRaw(os.stream.useChannel('main')); + this.connection2 = markRaw(stream.useChannel('main')); this.connection2.on('follow', onChangeFollowing); this.connection2.on('unfollow', onChangeFollowing); } else if (this.src == 'local') { endpoint = 'notes/local-timeline'; - this.connection = markRaw(os.stream.useChannel('localTimeline')); + this.connection = markRaw(stream.useChannel('localTimeline')); this.connection.on('note', prepend); } else if (this.src == 'social') { endpoint = 'notes/hybrid-timeline'; - this.connection = markRaw(os.stream.useChannel('hybridTimeline')); + this.connection = markRaw(stream.useChannel('hybridTimeline')); this.connection.on('note', prepend); } else if (this.src == 'global') { endpoint = 'notes/global-timeline'; - this.connection = markRaw(os.stream.useChannel('globalTimeline')); + this.connection = markRaw(stream.useChannel('globalTimeline')); this.connection.on('note', prepend); } else if (this.src == 'mentions') { endpoint = 'notes/mentions'; - this.connection = markRaw(os.stream.useChannel('main')); + this.connection = markRaw(stream.useChannel('main')); this.connection.on('mention', prepend); } else if (this.src == 'directs') { endpoint = 'notes/mentions'; @@ -130,14 +131,14 @@ export default defineComponent({ prepend(note); } }; - this.connection = markRaw(os.stream.useChannel('main')); + this.connection = markRaw(stream.useChannel('main')); this.connection.on('mention', onNote); } else if (this.src == 'list') { endpoint = 'notes/user-list-timeline'; this.query = { listId: this.list }; - this.connection = markRaw(os.stream.useChannel('userList', { + this.connection = markRaw(stream.useChannel('userList', { listId: this.list })); this.connection.on('note', prepend); @@ -148,7 +149,7 @@ export default defineComponent({ this.query = { channelId: this.channel }; - this.connection = markRaw(os.stream.useChannel('channel', { + this.connection = markRaw(stream.useChannel('channel', { channelId: this.channel })); this.connection.on('note', prepend); diff --git a/packages/client/src/components/user-select-dialog.vue b/packages/client/src/components/user-select-dialog.vue index ba2975478b..dbef34d547 100644 --- a/packages/client/src/components/user-select-dialog.vue +++ b/packages/client/src/components/user-select-dialog.vue @@ -1,5 +1,5 @@ -