From 5d931fc41b051f424ba0238409a747d8bcf0a7dd Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Sun, 30 Jul 2023 13:11:48 -0700 Subject: [PATCH 1/5] chore: :busts_in_silhouette: calckey.social -> firefish.social --- CHANGELOG.md | 4 +-- patrons.json | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a30385efe8..eef5bce467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,7 +67,7 @@ Closes #10313 - Fix: :bug: don't convert time since epoch for ratelimit -https://calckey.social/notes/9gkasnzglmi07rpa +https://firefish.social/notes/9gkasnzglmi07rpa - Fix: :bug: fix tapping parent on mobile causing side effects @@ -1834,7 +1834,7 @@ Closes #9843 - Fix: :recycle: use locale for error -https://calckey.social/notes/9fippqiwhl287b5m +https://firefish.social/notes/9fippqiwhl287b5m - Fix mfm-cheat-sheet styling diff --git a/patrons.json b/patrons.json index 8978f4c7c8..738083ec98 100644 --- a/patrons.json +++ b/patrons.json @@ -1,13 +1,13 @@ { "patrons": [ - "@atomicpoet@calckey.social", + "@atomicpoet@firefish.social", "@shoq@mastodon.social", "@pikadude@erisly.social", "@sage@stop.voring.me", "@sky@therian.club", "@panos@electricrequiem.com", "@redhunt07@www.foxyhole.io", - "@griff@calckey.social", + "@griff@firefish.social", "@cafkafk@ck.cafkafk.com", "@privateger@plasmatrap.com", "@effye@toot.thoughtworks.com", @@ -17,56 +17,56 @@ "@topher@mastodon.online", "@hanicef@stop.voring.me", "@nmkj@calckey.jp", - "@unattributed@calckey.social", + "@unattributed@firefish.social", "@cody@misskey.codingneko.com", "@kate@blahaj.zone", "@emtk@mkkey.net", - "@jovikowi@calckey.social", - "@padraig@calckey.social", + "@jovikowi@firefish.social", + "@padraig@firefish.social", "@pancakes@cats.city", - "@theresmiling@calckey.social", - "@kristian@calckey.social", + "@theresmiling@firefish.social", + "@kristian@firefish.social", "@jo@blahaj.zone", - "@narF@calckey.social", + "@narF@firefish.social", "@AlderForrest@raining.anvil.top", - "@box464@calckey.social", - "@MariaTheMartian@calckey.social", - "@nisemikol@calckey.social", + "@box464@firefish.social", + "@MariaTheMartian@firefish.social", + "@nisemikol@firefish.social", "@smallpatatas@blahaj.zone", "@bayra@stop.voring.me", "@frost@wolfdo.gg", "@joebiden@fuckgov.org", - "@nyaa@calckey.social", - "@Dan@calckey.social", - "@dana@calckey.social", - "@Jdreben@calckey.social", + "@nyaa@firefish.social", + "@Dan@firefish.social", + "@dana@firefish.social", + "@Jdreben@firefish.social", "@natalie@prismst.one", "@KelsonV@wandering.shop", - "@breakfastmtn@calckey.social", + "@breakfastmtn@firefish.social", "@richardazia@mastodon.social", - "@joestone@calckey.social", - "@aj@calckey.social", + "@joestone@firefish.social", + "@aj@firefish.social", "@zepfanman@ramblingreaders.org", "@kimby@stop.voring.me", "@fyrfli@fyrfli.social", "@riversidebryan@firefish.lgbt", "@aRubes@sloth.run", - "@andreasdotorg@calckey.social", + "@andreasdotorg@firefish.social", "@ozzy@calckey.online", "@leni@windycity.style", "@mhzmodels@calckey.art", - "@ReflexVE@calckey.social", - "@mark@calckey.social", + "@ReflexVE@firefish.social", + "@mark@firefish.social", "@skyizwhite@himagine.club", - "@Uwu@calckey.social", - "@jGoose@calckey.social", + "@Uwu@firefish.social", + "@jGoose@firefish.social", "@kunev@blewsky.social", "@Simoto@electricrequiem.com", - "@Evoterra@calckey.social", + "@Evoterra@firefish.social", "@LauraLangdon@procial.tchncs.de", "@mho@social.heise.de", - "@richardazia@calckey.social", - "@blues653@calckey.social", + "@richardazia@firefish.social", + "@blues653@firefish.social", "@rafale_blue@calc.04.si", "@esm@lethallava.land", "@vmstan@vmst.io", @@ -74,33 +74,33 @@ "@renere@distance.blue", "@theking@kitsunes.club", "@toof@fedi.toofie.net", - "@Punko@calckey.social", - "@joesbrat67@calckey.social", - "@arth@calckey.social", + "@Punko@firefish.social", + "@joesbrat67@firefish.social", + "@arth@firefish.social", "@octofloofy@ck.octofloofy.ink", "@pauliehedron@infosec.town", "@soulthunk@lethallava.land", "@bumble@ibe.social", - "@DarrenNevares@calckey.social", - "@irfan@calckey.social", + "@DarrenNevares@firefish.social", + "@irfan@firefish.social", "@dvd@dvd.chat", "@charlie2alpha@electricrequiem.com", "@arndot@layer8.space", "@ryan@c.ryanccn.dev", - "@lapastora_deprova@calckey.social", - "@rameez@calckey.social", + "@lapastora_deprova@firefish.social", + "@rameez@firefish.social", "@dracoling@firetribe.org", - "@Space6host@calckey.social", + "@Space6host@firefish.social", "@zakalwe@plasmatrap.com", - "@seasicksailor@calckey.social", - "@geerue@calckey.social", + "@seasicksailor@firefish.social", + "@geerue@firefish.social", "@WXFanatic@m.ai6yr.org", "@Hunkabilly@calckey.world", - "@samleegray@calckey.social", + "@samleegray@firefish.social", "@schwarzewald@kodow.net", - "@Conatusprinciple@calckey.social", + "@Conatusprinciple@firefish.social", "@183231bcb@firefish.lgbt", - "@wiase@calckey.social", + "@wiase@firefish.social", "@leonieke@vitaulium.nl", "@soulfire@wackywolf.xyz", "@elbullazul@pub.elbullazul.com", @@ -110,8 +110,8 @@ "@hryggrbyr@ibe.social" ], "sponsors": [ - "@atomicpoet@calckey.social", - "@unattributed@calckey.social", + "@atomicpoet@firefish.social", + "@unattributed@firefish.social", "@jtbennett@noc.social", "\nInterkosmos Link" ] From 32fac53e8d950d60e7cb0effa33846e75131b6e7 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sun, 30 Jul 2023 16:27:13 -0400 Subject: [PATCH 2/5] feat: backend debug in vscode --- .gitignore | 1 + .vscode/launch.json | 20 ++++++++++++++++++++ package.json | 2 ++ packages/backend/native-utils/package.json | 2 +- packages/backend/package.json | 1 + packages/client/package.json | 1 + packages/firefish-js/package.json | 1 + packages/megalodon/package.json | 1 + packages/sw/package.json | 1 + 9 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index ad887b7e2a..0185b4e495 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Visual Studio Code /.vscode !/.vscode/extensions.json +!/.vscode/launch.json # Intelij-IDEA /.idea diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..84ce98609a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch PNPM Debug Script", + "skipFiles": [ + "/**" + ], + "runtimeExecutable": "pnpm", + "runtimeArgs": [ + "run", "debug" + ] + } + ] +} diff --git a/package.json b/package.json index 1d20b1f392..7e5073be58 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "dev": "pnpm node ./scripts/dev.js", "dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start", "lint": "pnpm -r --parallel run lint", + "debug": "pnpm run build:debug && pnpm run start", + "build:debug": "pnpm -r --parallel run build:debug && pnpm run gulp", "cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts", "cy:run": "cypress run", "e2e": "start-server-and-test start:test http://localhost:61812 cy:run", diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json index 962b4bc4c4..93a6497f53 100644 --- a/packages/backend/native-utils/package.json +++ b/packages/backend/native-utils/package.json @@ -37,7 +37,7 @@ "build": "pnpm run build:napi && pnpm run build:migration", "build:napi": "napi build --features napi --platform --release ./built/", "build:migration": "cargo build --locked --release --manifest-path ./migration/Cargo.toml && cp ./target/release/migration ./built/migration", - "build:debug": "napi build --platform ./built/ && cargo build --manifest-path ./migration/Cargo.toml", + "build:debug": "napi build --features napi --platform ./built/ && cargo build --locked --manifest-path ./migration/Cargo.toml && cp -v ./target/debug/migration ./built/migration", "prepublishOnly": "napi prepublish -t npm", "test": "pnpm run cargo:test && pnpm run build:napi && ava", "universal": "napi universal", diff --git a/packages/backend/package.json b/packages/backend/package.json index cc8f4747ec..9288ed92f5 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -14,6 +14,7 @@ "revertmigration:cargo": "./native-utils/built/migration down", "check:connect": "node ./check_connect.js", "build": "pnpm swc src -d built -D", + "build:debug": "pnpm swc src -d built -s -D", "watch": "pnpm swc src -d built -D -w", "lint": "pnpm rome check --apply *", "mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha", diff --git a/packages/client/package.json b/packages/client/package.json index 43983c460a..a2ee694d70 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -4,6 +4,7 @@ "scripts": { "watch": "pnpm vite build --watch --mode development", "build": "pnpm vite build", + "build:debug": "pnpm run build", "lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue", "lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache", "format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata" diff --git a/packages/firefish-js/package.json b/packages/firefish-js/package.json index bcee951765..7cdd419ec7 100644 --- a/packages/firefish-js/package.json +++ b/packages/firefish-js/package.json @@ -6,6 +6,7 @@ "types": "./built/index.d.ts", "scripts": { "build": "pnpm swc src -d built -D", + "build:debug": "pnpm swc src -d built -s -D", "render": "pnpm run build && pnpm run api && pnpm run api-prod && cp temp/firefish-js.api.json etc/ && pnpm run api-doc", "tsd": "tsc && tsd", "api": "pnpm api-extractor run --local --verbose", diff --git a/packages/megalodon/package.json b/packages/megalodon/package.json index dea59b5790..e9e30abe12 100644 --- a/packages/megalodon/package.json +++ b/packages/megalodon/package.json @@ -5,6 +5,7 @@ "typings": "./lib/src/index.d.ts", "scripts": { "build": "tsc -p ./", + "build:debug": "pnpm run build", "lint": "pnpm rome check **/*.ts --apply", "format": "pnpm rome format --write src/**/*.ts", "doc": "typedoc --out ../docs ./src", diff --git a/packages/sw/package.json b/packages/sw/package.json index c86c15eadc..6118e249a2 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -3,6 +3,7 @@ "private": true, "scripts": { "build": "webpack", + "build:debug": "pnpm run build", "watch": "pnpm swc src -d built -D -w", "lint": "pnpm rome check **/*.ts --apply", "format": "pnpm rome format * --write" From d76b4f23210413d3f75129964ee297f5642facee Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Sun, 30 Jul 2023 13:30:25 -0700 Subject: [PATCH 3/5] fix: :bug: rel=me verification with multiple rels besides me Closes #10595 --- packages/backend/src/services/fetch-rel-me.ts | 11 +++++++---- packages/client/src/pages/settings/profile.vue | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/services/fetch-rel-me.ts b/packages/backend/src/services/fetch-rel-me.ts index f7dbf72c1e..3e9f3c1184 100644 --- a/packages/backend/src/services/fetch-rel-me.ts +++ b/packages/backend/src/services/fetch-rel-me.ts @@ -6,10 +6,13 @@ async function getRelMeLinks(url: string): Promise { try { const html = await getHtml(url); const dom = new JSDOM(html); - const relMeLinks = [ - ...dom.window.document.querySelectorAll("a[rel='me']"), - ...dom.window.document.querySelectorAll("link[rel='me']"), - ].map((a) => (a as HTMLAnchorElement | HTMLLinkElement).href); + const allLinks = [...dom.window.document.querySelectorAll("a, link")]; + const relMeLinks = allLinks + .filter((a) => { + const relAttribute = a.getAttribute("rel"); + return relAttribute ? relAttribute.split(" ").includes("me") : false; + }) + .map((a) => (a as HTMLAnchorElement | HTMLLinkElement).href); return relMeLinks; } catch { return []; diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue index 3b94a82488..fa33ac8876 100644 --- a/packages/client/src/pages/settings/profile.vue +++ b/packages/client/src/pages/settings/profile.vue @@ -127,8 +127,8 @@ From 432f840efe2d626fecec0d39a6a4e7d586137ca7 Mon Sep 17 00:00:00 2001 From: John Regan Date: Sun, 30 Jul 2023 20:38:57 +0000 Subject: [PATCH 4/5] fix iOS video playback (fixes #10517) --- .../src/server/file/byte-range-readable.ts | 221 ++++++++++++++++++ .../src/server/file/send-drive-file.ts | 104 +++++++-- .../src/services/drive/internal-storage.ts | 5 + packages/client/src/components/MkMedia.vue | 1 + 4 files changed, 309 insertions(+), 22 deletions(-) create mode 100644 packages/backend/src/server/file/byte-range-readable.ts diff --git a/packages/backend/src/server/file/byte-range-readable.ts b/packages/backend/src/server/file/byte-range-readable.ts new file mode 100644 index 0000000000..d80e783cca --- /dev/null +++ b/packages/backend/src/server/file/byte-range-readable.ts @@ -0,0 +1,221 @@ +import { Readable, ReadableOptions } from "node:stream"; +import { Buffer, constants as BufferConstants } from "node:buffer"; +import * as fs from "node:fs"; + +interface ByteRange { + start: bigint; + end: bigint; + size: bigint; +} + +const BOUNDARY_CHARS = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; +const BYTERANGE_SPEC_REGEX = /^bytes=(.+)$/; +const BYTERANGE_REGEX = /(\d*)-(\d*)/; + +const BIGINT_0 = BigInt(0); +const BIGINT_1 = BigInt(1); +const BOUNDARY_SIZE = 40; + +function extractRanges( + fileSize: bigint, + maxByteRanges: number, + rangeHeaderValue: string, +): ByteRange[] { + const ranges: ByteRange[] = []; + + if (!rangeHeaderValue) return ranges; + + const rangeSpecMatch = rangeHeaderValue.match(BYTERANGE_SPEC_REGEX); + if (!rangeSpecMatch) return []; + + const rangeSpecs = rangeSpecMatch[1].split(","); + for (let i = 0; i < rangeSpecs.length; i = i + 1) { + const byteRange = rangeSpecs[i].match(BYTERANGE_REGEX); + if (!byteRange) return []; + + let start: bigint; + let end: bigint; + let size: bigint; + + if (byteRange[1]) { + start = BigInt(byteRange[1]); + } + + if (byteRange[2]) { + end = BigInt(byteRange[2]); + } + + if (start === undefined && end === undefined) { + /* some invalid range like bytes=- */ + return []; + } + + if (start === undefined) { + /* end-of-file range like -500 */ + start = fileSize - end; + end = fileSize - BIGINT_1; + if (start < BIGINT_0) return []; /* range larger than file, return */ + } + + if (end === undefined) { + /* range like 0- */ + end = fileSize - BIGINT_1; + } + + if (start > end || end >= fileSize) { + /* return empty range to issue regular 200 */ + return []; + } + size = end - start + BIGINT_1; + + if (1 > maxByteRanges - ranges.length) return []; + + ranges.push({ + start: start, + end: end, + size: size, + }); + } + + return ranges; +} + +function createBoundary(len: number): string { + let chars = []; + for (let i = 0; i < len; i = i + 1) { + chars[i] = BOUNDARY_CHARS.charAt( + Math.floor(Math.random() * BOUNDARY_CHARS.length), + ); + } + return chars.join(""); +} + +class ByteRangeReadable extends Readable { + size: bigint; /* the total size in bytes */ + boundary: string; /* boundary marker to use in multipart headers */ + + private fd: number; + private ranges: ByteRange[]; + private index: number; /* index within ranges */ + private position: bigint; + private end: bigint; + private contentType: string; + private fileSize: bigint; + private headers: Buffer[]; + private trailer: Buffer; + + static parseByteRanges( + fileSize: bigint, + maxByteRanges: number, + rangeHeaderValue?: string, + ): ByteRange[] { + return extractRanges(fileSize, maxByteRanges, rangeHeaderValue); + } + + private createPartHeader(range: ByteRange): Buffer { + return Buffer.from( + [ + "", + `--${this.boundary}`, + `Content-Type: ${this.contentType}`, + `Content-Range: bytes ${range.start}-${range.end}/${this.fileSize}`, + "", + "", + ].join("\r\n"), + ); + } + + constructor( + fd: number, + fileSize: bigint, + ranges: ByteRange[], + contentType: string, + opts?: ReadableOptions, + ) { + super(opts); + + if (ranges.length === 0) { + throw Error("this requires at least 1 byte range"); + } + + this.fd = fd; + this.ranges = ranges; + this.fileSize = fileSize; + this.contentType = contentType; + + this.position = BIGINT_1; + this.end = BIGINT_0; + this.index = -1; + this.headers = []; + + this.size = BIGINT_0; + + if (this.ranges.length === 1) { + this.size = this.ranges[0].size; + } else { + this.boundary = createBoundary(BOUNDARY_SIZE); + this.ranges.forEach((r) => { + const header = this.createPartHeader(r); + this.headers.push(header); + + this.size += BigInt(header.length) + r.size; + }); + this.trailer = Buffer.from(`\r\n--${this.boundary}--\r\n`); + this.size += BigInt(this.trailer.length); + } + } + + _read(n) { + if (this.index == this.ranges.length) { + this.push(null); + return; + } + + if (this.position > this.end) { + /* move ahead to the next index */ + this.index++; + + if (this.index === this.ranges.length) { + if (this.trailer) { + this.push(this.trailer); + return; + } + this.push(null); + return; + } + + this.position = this.ranges[this.index].start; + this.end = this.ranges[this.index].end; + + if (this.ranges.length > 1) { + this.push(this.headers[this.index]); + return; + } + } + + const max = this.end - this.position + BIGINT_1; + + if (n > max) n = Number(max); + const buf = Buffer.alloc(n); + + fs.read(this.fd, buf, 0, n, this.position, (err, bytesRead) => { + if (err) { + this.destroy(err); + return; + } + if (bytesRead == 0) { + /* something seems to have gone wrong? */ + this.push(null); + return; + } + + if (bytesRead > n) bytesRead = n; + + this.position += BigInt(bytesRead); + this.push(buf.slice(0, bytesRead)); + }); + } +} + +export { ByteRange, ByteRangeReadable }; diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index 0877369025..9c70770910 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -14,6 +14,7 @@ import { detectType } from "@/misc/get-file-info.js"; import { convertToWebp } from "@/services/drive/image-processor.js"; import { GenerateVideoThumbnail } from "@/services/drive/generate-video-thumbnail.js"; import { StatusError } from "@/misc/fetch.js"; +import { ByteRangeReadable } from "./byte-range-readable.js"; import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; const _filename = fileURLToPath(import.meta.url); @@ -21,6 +22,8 @@ const _dirname = dirname(_filename); const assets = `${_dirname}/../../server/file/assets/`; +const MAX_BYTE_RANGES = 10; + const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => { serverLogger.error(e); @@ -122,31 +125,88 @@ export default async function (ctx: Koa.Context) { return; } + let contentType; + let filename; + let fileHandle; + if (isThumbnail || isWebpublic) { const { mime, ext } = await detectType(InternalStorage.resolvePath(key)); - const filename = rename(file.name, { - suffix: isThumbnail ? "-thumb" : "-web", - extname: ext ? `.${ext}` : undefined, - }).toString(); + (contentType = FILE_TYPE_BROWSERSAFE.includes(mime) + ? mime + : "application/octet-stream"), + (filename = rename(file.name, { + suffix: isThumbnail ? "-thumb" : "-web", + extname: ext ? `.${ext}` : undefined, + }).toString()); - ctx.body = InternalStorage.read(key); - ctx.set( - "Content-Type", - FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : "application/octet-stream", - ); - ctx.set("Cache-Control", "max-age=31536000, immutable"); - ctx.set("Content-Disposition", contentDisposition("inline", filename)); + fileHandle = await InternalStorage.open(key, "r"); } else { - const readable = InternalStorage.read(file.accessKey!); - readable.on("error", commonReadableHandlerGenerator(ctx)); - ctx.body = readable; - ctx.set( - "Content-Type", - FILE_TYPE_BROWSERSAFE.includes(file.type) - ? file.type - : "application/octet-stream", - ); - ctx.set("Cache-Control", "max-age=31536000, immutable"); - ctx.set("Content-Disposition", contentDisposition("inline", file.name)); + (contentType = FILE_TYPE_BROWSERSAFE.includes(file.type) + ? file.type + : "application/octet-stream"), + (filename = file.name); + fileHandle = await InternalStorage.open(file.accessKey!, "r"); + } + + // We can let Koa evaluate conditionals by setting + // the status to 200, along with the lastModified + // and etag properties, then checking ctx.fresh. + // Additionally, Range is ignored if a conditional GET would + // result in a 304 response, so we can return early here. + + ctx.status = 200; + ctx.etag = file.md5; + ctx.lastModified = file.createdAt; + + // When doing a conditional request, we MUST return a "Cache-Control" header + // if a normal 200 response would have included. + ctx.set("Cache-Control", "max-age=31536000, immutable"); + + if (ctx.fresh) { + ctx.status = 304; + return; + } + + ctx.length = file.size; + ctx.set("Content-Disposition", contentDisposition("inline", filename)); + ctx.set("Content-Type", contentType); + + const ranges = ByteRangeReadable.parseByteRanges( + BigInt(file.size), + MAX_BYTE_RANGES, + ctx.headers["range"], + ); + const readable = + ranges.length === 0 + ? fileHandle.createReadStream() + : new ByteRangeReadable( + fileHandle.fd, + BigInt(file.size), + ranges, + contentType, + ); + readable.on("error", commonReadableHandlerGenerator(ctx)); + ctx.body = readable; + + if (ranges.length === 0) { + ctx.set("Accept-Ranges", "bytes"); + } else { + ctx.status = 206; + ctx.length = readable.size; + readable.on("close", async () => { + await fileHandle.close(); + }); + + if (ranges.length === 1) { + ctx.set( + "Content-Range", + `bytes ${ranges[0].start}-${ranges[0].end}/${file.size}`, + ); + } else { + ctx.set( + "Content-Type", + `multipart/byteranges; boundary=${readable.boundary}`, + ); + } } } diff --git a/packages/backend/src/services/drive/internal-storage.ts b/packages/backend/src/services/drive/internal-storage.ts index bccb123be4..b2a663b3ea 100644 --- a/packages/backend/src/services/drive/internal-storage.ts +++ b/packages/backend/src/services/drive/internal-storage.ts @@ -1,4 +1,5 @@ import * as fs from "node:fs"; +import * as fsPromises from "node:fs/promises"; import * as Path from "node:path"; import { fileURLToPath } from "node:url"; import { dirname } from "node:path"; @@ -13,6 +14,10 @@ export class InternalStorage { public static resolvePath = (key: string) => Path.resolve(InternalStorage.path, key); + public static open(key: string, flags: string) { + return fsPromises.open(InternalStorage.resolvePath(key), flags); + } + public static read(key: string) { return fs.createReadStream(InternalStorage.resolvePath(key)); } diff --git a/packages/client/src/components/MkMedia.vue b/packages/client/src/components/MkMedia.vue index 7d9e3f90de..bbacc669d5 100644 --- a/packages/client/src/components/MkMedia.vue +++ b/packages/client/src/components/MkMedia.vue @@ -53,6 +53,7 @@ :aria-label="media.comment" preload="none" controls + playsinline @contextmenu.stop > From 4de05b6e053823593678ee7107042220b4852002 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sun, 30 Jul 2023 21:15:33 +0000 Subject: [PATCH 5/5] ci: run build:debug and cache artifacts to compile native-utils faster --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf458ee75a..9d4a51d7a6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,7 +38,7 @@ testCommit: stage: build script: - pnpm i --frozen-lockfile - - pnpm run build + - pnpm run build:debug - pnpm run migrate only: - main @@ -66,4 +66,4 @@ cache: - node_modules/ - packages/*/node_modules/ - packages/backend/native-utils/node_modules/ - - packages/backend/native-utils/.cargo/ + - packages/backend/native-utils/target/