From 2da19d96bebbc5730336fa97a154f812225edfe8 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Sat, 6 Jan 2024 13:58:18 +0900 Subject: [PATCH 01/20] wip --- .../frontend/src/components/MkMediaVideo.vue | 367 ++++++++++++++---- packages/frontend/src/filters/hms.ts | 27 ++ packages/frontend/src/scripts/device-kind.ts | 7 + 3 files changed, 334 insertions(+), 67 deletions(-) create mode 100644 packages/frontend/src/filters/hms.ts diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index f9dba0b15af7..6376e47b2246 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -4,39 +4,70 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/filters/hms.ts b/packages/frontend/src/filters/hms.ts new file mode 100644 index 000000000000..0885f4118c06 --- /dev/null +++ b/packages/frontend/src/filters/hms.ts @@ -0,0 +1,27 @@ +export default (ms: number) => { + const res: string[] = []; + + // ミリ秒を秒に変換 + let seconds = Math.floor(ms / 1000); + + // 時間を計算 + let hours = Math.floor(seconds / 3600); + if (hours > 0) res.push(format(hours)); + seconds %= 3600; + + // 分を計算 + let minutes = Math.floor(seconds / 60); + res.push(format(minutes)); + seconds %= 60; + + // 残った秒数を取得 + seconds = seconds % 60; + res.push(format(seconds)); + + // 結果を返す + return res.join(':'); +}; + +function format(n: number) { + return n.toString().padStart(2, '0'); +} diff --git a/packages/frontend/src/scripts/device-kind.ts b/packages/frontend/src/scripts/device-kind.ts index 3843052a2430..218eb718b109 100644 --- a/packages/frontend/src/scripts/device-kind.ts +++ b/packages/frontend/src/scripts/device-kind.ts @@ -11,6 +11,13 @@ const ua = navigator.userAgent.toLowerCase(); const isTablet = /ipad/.test(ua) || (/mobile|iphone|android/.test(ua) && window.innerWidth > 700); const isSmartphone = !isTablet && /mobile|iphone|android/.test(ua); +const isIPhone = /iphone|ipod/gi.test(ua) && navigator.maxTouchPoints > 1; +// navigator.platform may be deprecated but this check is still required +const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1; +const isIos = /ipad|iphone|ipod/gi.test(ua) && navigator.maxTouchPoints > 1; + +export const isFullscreenNotSupported = isIPhone || isIos; + export const deviceKind: 'smartphone' | 'tablet' | 'desktop' = defaultStore.state.overridedDeviceKind ? defaultStore.state.overridedDeviceKind : isSmartphone ? 'smartphone' : isTablet ? 'tablet' From f159fc80c6be2a259b790f26fd5190706a391e4e Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Sat, 6 Jan 2024 15:16:10 +0900 Subject: [PATCH 02/20] =?UTF-8?q?(fix)=20`/files`=20=E3=82=92=E3=83=90?= =?UTF-8?q?=E3=82=A4=E3=83=88=E3=83=AC=E3=83=B3=E3=82=B8=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=82=B9=E3=83=88=E3=81=AB=E5=AF=BE=E5=BF=9C=E3=81=95?= =?UTF-8?q?=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/server/FileServerService.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index f59996ce17f5..346b2b6e6817 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -168,6 +168,29 @@ export class FileServerService { } if (!image) { + if (request.headers.range) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + if (end > file.file.size) { + end = file.file.size - 1; + } + + image = { + data: fs.createReadStream(file.path, { + start, + end, + }), + ext: file.ext, + type: file.mime, + }; + + const chunksize = end - start + 1; + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + } image = { data: fs.createReadStream(file.path), ext: file.ext, @@ -203,11 +226,54 @@ export class FileServerService { reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.mime) ? file.mime : 'application/octet-stream'); reply.header('Cache-Control', 'max-age=31536000, immutable'); reply.header('Content-Disposition', contentDisposition('inline', filename)); + + if (request.headers.range) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + const fileStream = fs.createReadStream(file.path, { + start, + end, + }); + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + reply.code(206); + return fileStream; + } + return fs.createReadStream(file.path); } else { reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.file.type) ? file.file.type : 'application/octet-stream'); reply.header('Cache-Control', 'max-age=31536000, immutable'); reply.header('Content-Disposition', contentDisposition('inline', file.filename)); + + if (request.headers.range) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + console.log(end); + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + const fileStream = fs.createReadStream(file.path, { + start, + end, + }); + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + reply.code(206); + return fileStream; + } + return fs.createReadStream(file.path); } } catch (e) { From fa9353350e5b6ae682480c868e34e9b08969c4f2 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Sat, 6 Jan 2024 17:32:45 +0900 Subject: [PATCH 03/20] video --- .../frontend/src/components/MkMediaRange.vue | 142 ++++++++ .../frontend/src/components/MkMediaVideo.vue | 319 ++++++++++++++---- 2 files changed, 399 insertions(+), 62 deletions(-) create mode 100644 packages/frontend/src/components/MkMediaRange.vue diff --git a/packages/frontend/src/components/MkMediaRange.vue b/packages/frontend/src/components/MkMediaRange.vue new file mode 100644 index 000000000000..86d8683f2ab0 --- /dev/null +++ b/packages/frontend/src/components/MkMediaRange.vue @@ -0,0 +1,142 @@ + + + + + + + + diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index 6376e47b2246..d34219e49e78 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -4,15 +4,25 @@ SPDX-License-Identifier: AGPL-3.0-only --> From 81b50498eee737cc32751058387c19342ac32d97 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Sat, 6 Jan 2024 18:27:50 +0900 Subject: [PATCH 04/20] audio --- locales/index.d.ts | 2 + locales/ja-JP.yml | 2 + .../frontend/src/components/MkMediaAudio.vue | 347 ++++++++++++++++++ .../frontend/src/components/MkMediaBanner.vue | 13 +- .../frontend/src/components/MkMediaRange.vue | 16 +- .../frontend/src/components/MkMediaVideo.vue | 17 +- packages/frontend/src/filters/hms.ts | 39 +- 7 files changed, 394 insertions(+), 42 deletions(-) create mode 100644 packages/frontend/src/components/MkMediaAudio.vue diff --git a/locales/index.d.ts b/locales/index.d.ts index 3937784153d0..b74e4b096c1a 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1055,6 +1055,8 @@ export interface Locale { "noteIdOrUrl": string; "video": string; "videos": string; + "audio": string; + "audioFiles": string; "dataSaver": string; "accountMigration": string; "accountMoved": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 77f9a9ec0f13..e76bb4865683 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1052,6 +1052,8 @@ limitWidthOfReaction: "リアクションの最大横幅を制限し、縮小し noteIdOrUrl: "ノートIDまたはURL" video: "動画" videos: "動画" +audio: "音声" +audioFiles: "音声" dataSaver: "データセーバー" accountMigration: "アカウントの移行" accountMoved: "このユーザーは新しいアカウントに移行しました:" diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue new file mode 100644 index 000000000000..453b17fe3ba9 --- /dev/null +++ b/packages/frontend/src/components/MkMediaAudio.vue @@ -0,0 +1,347 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index 3f8fef6632eb..b21960a4900c 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -5,20 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only