diff --git a/packages/backend/src/queue/processors/db/export-notes.ts b/packages/backend/src/queue/processors/db/export-notes.ts index de8fac05b..bf53f8360 100644 --- a/packages/backend/src/queue/processors/db/export-notes.ts +++ b/packages/backend/src/queue/processors/db/export-notes.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { Users, Notes, Polls } from "@/models/index.js"; +import { Users, Notes, Polls, DriveFiles } from "@/models/index.js"; import { MoreThan } from "typeorm"; import type { Note } from "@/models/entities/note.js"; import type { Poll } from "@/models/entities/poll.js"; @@ -75,7 +75,7 @@ export async function exportNotes( if (note.hasPoll) { poll = await Polls.findOneByOrFail({ noteId: note.id }); } - const content = JSON.stringify(serialize(note, poll)); + const content = JSON.stringify(await serialize(note, poll)); const isFirst = exportedNotesCount === 0; await write(isFirst ? content : ",\n" + content); exportedNotesCount++; @@ -112,15 +112,16 @@ export async function exportNotes( done(); } -function serialize( +async function serialize( note: Note, poll: Poll | null = null, -): Record<string, unknown> { +): Promise<Record<string, unknown>> { return { id: note.id, text: note.text, createdAt: note.createdAt, fileIds: note.fileIds, + files: await DriveFiles.packMany(note.fileIds), replyId: note.replyId, renoteId: note.renoteId, poll: poll, diff --git a/packages/backend/src/queue/processors/db/import-calckey-post.ts b/packages/backend/src/queue/processors/db/import-calckey-post.ts index 28e794aa0..945c50d63 100644 --- a/packages/backend/src/queue/processors/db/import-calckey-post.ts +++ b/packages/backend/src/queue/processors/db/import-calckey-post.ts @@ -3,6 +3,8 @@ import create from "@/services/note/create.js"; import { Users } from "@/models/index.js"; import type { DbUserImportMastoPostJobData } from "@/queue/types.js"; import { queueLogger } from "../../logger.js"; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; import type Bull from "bull"; const logger = queueLogger.createSubLogger("import-calckey-post"); @@ -29,10 +31,25 @@ export async function importCkPost( done(); return; } + const urls = (post.files || []) + .map((x: any) => x.url) + .filter((x: String) => x.startsWith("http")); + const files: DriveFile[] = []; + for (const url of urls) { + try { + const file = await uploadFromUrl({ + url: url, + user: user, + }); + files.push(file); + } catch (e) { + logger.error(`Skipped adding file to drive: ${url}`); + } + } const { text, cw, localOnly, createdAt } = Post.parse(post); const note = await create(user, { createdAt: createdAt, - files: undefined, + files: files.length == 0 ? undefined : files, poll: undefined, text: text || undefined, reply: null, diff --git a/packages/backend/src/queue/processors/db/import-masto-post.ts b/packages/backend/src/queue/processors/db/import-masto-post.ts index efa4adf3f..05166b085 100644 --- a/packages/backend/src/queue/processors/db/import-masto-post.ts +++ b/packages/backend/src/queue/processors/db/import-masto-post.ts @@ -6,6 +6,8 @@ import type Bull from "bull"; import { htmlToMfm } from "@/remote/activitypub/misc/html-to-mfm.js"; import { resolveNote } from "@/remote/activitypub/models/note.js"; import { Note } from "@/models/entities/note.js"; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; const logger = queueLogger.createSubLogger("import-masto-post"); @@ -43,9 +45,25 @@ export async function importMastoPost( throw e; } job.progress(80); + const urls = post.object.attachment + .map((x: any) => x.url) + .filter((x: String) => x.startsWith("http")); + const files: DriveFile[] = []; + for (const url of urls) { + try { + const file = await uploadFromUrl({ + url: url, + user: user, + }); + files.push(file); + } catch (e) { + logger.error(`Skipped adding file to drive: ${url}`); + } + } + const note = await create(user, { createdAt: new Date(post.object.published), - files: undefined, + files: files.length == 0 ? undefined : files, poll: undefined, text: text || undefined, reply, diff --git a/packages/client/src/components/MkEmojiPicker.vue b/packages/client/src/components/MkEmojiPicker.vue index 09d61518d..2a797f56a 100644 --- a/packages/client/src/components/MkEmojiPicker.vue +++ b/packages/client/src/components/MkEmojiPicker.vue @@ -195,7 +195,7 @@ const props = withDefaults( ); const emit = defineEmits<{ - (ev: "chosen", v: string): void; + (ev: "chosen", v: string, ev: MouseEvent): void; }>(); const search = ref<HTMLInputElement>(); @@ -436,7 +436,7 @@ function chosen(emoji: any, ev?: MouseEvent) { } const key = getKey(emoji); - emit("chosen", key); + emit("chosen", key, ev); // 最近使った絵文字更新 if (!pinned.value.includes(key)) { diff --git a/packages/client/src/components/MkEmojiPickerDialog.vue b/packages/client/src/components/MkEmojiPickerDialog.vue index 28cc1d215..99afe9b6a 100644 --- a/packages/client/src/components/MkEmojiPickerDialog.vue +++ b/packages/client/src/components/MkEmojiPickerDialog.vue @@ -58,29 +58,16 @@ const emit = defineEmits<{ const modal = ref<InstanceType<typeof MkModal>>(); const picker = ref<InstanceType<typeof MkEmojiPicker>>(); -const isShiftKeyPressed = ref(false); -const keydownHandler = (e) => { - if (e.key === "Shift") { - isShiftKeyPressed.value = true; - } -}; - -const keyupHandler = (e) => { - if (e.key === "Shift") { - isShiftKeyPressed.value = false; - } -}; function checkForShift(ev?: MouseEvent) { - if (!isShiftKeyPressed.value) { - modal.value?.close(ev); - } + if (ev?.shiftKey) return; + modal.value?.close(ev); } -function chosen(emoji: any) { +function chosen(emoji: any, ev: MouseEvent) { emit("done", emoji); - checkForShift(); + checkForShift(ev); } function opening() { @@ -91,16 +78,6 @@ function opening() { } picker.value?.focus(); } - -onMounted(() => { - window.addEventListener("keydown", keydownHandler); - window.addEventListener("keyup", keyupHandler); -}); - -onBeforeUnmount(() => { - window.removeEventListener("keydown", keydownHandler); - window.removeEventListener("keyup", keyupHandler); -}); </script> <style lang="scss" scoped> diff --git a/packages/client/src/components/MkMedia.vue b/packages/client/src/components/MkMedia.vue index 4c023f131..2cbb881f3 100644 --- a/packages/client/src/components/MkMedia.vue +++ b/packages/client/src/components/MkMedia.vue @@ -54,7 +54,7 @@ controls @contextmenu.stop > - <source :src="media.url" :type="media.type" /> + <source :src="media.url" :type="mediaType" /> </video> </VuePlyr> </template> @@ -80,7 +80,7 @@ </template> <script lang="ts" setup> -import { watch, ref } from "vue"; +import { watch, ref, computed } from "vue"; import VuePlyr from "vue-plyr"; import "vue-plyr/dist/vue-plyr.css"; import type * as misskey from "calckey-js"; @@ -107,6 +107,10 @@ const url = ? getStaticImageUrl(props.media.thumbnailUrl) : props.media.thumbnailUrl; +const mediaType = computed(() => { + return props.media.type === 'video/quicktime' ? 'video/mp4' : props.media.type; +}); + function captionPopup() { os.alert({ type: "info", diff --git a/packages/client/src/pages/settings/import-export.vue b/packages/client/src/pages/settings/import-export.vue index b2ac12cad..4a9286748 100644 --- a/packages/client/src/pages/settings/import-export.vue +++ b/packages/client/src/pages/settings/import-export.vue @@ -222,7 +222,7 @@ const importPosts = async (ev) => { const file = await selectFile(ev.currentTarget ?? ev.target); os.api("i/import-posts", { fileId: file.id, - signatureCheck: importType.value === "mastodon" ? true : false, + signatureCheck: false, }) .then(onImportSuccess) .catch(onError);