Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

圧縮ライブラリを変更 #5

Merged
merged 13 commits into from
Sep 28, 2024
10 changes: 5 additions & 5 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ let preview = $derived.by(() => {

let urlSearchParams = $page.url.searchParams;
if (urlSearchParams) {
const result = generateSearchParamsToText(urlSearchParams);
if (result) {
generateSearchParamsToText(urlSearchParams).then((result) => {
inputText = result;
}
});
}

function handleFileChange(event: Event) {
Expand All @@ -49,8 +48,9 @@ function handleFileChange(event: Event) {
}

function CopyUrlToClipboard(inputText: string) {
const url = generateCompressedNovelUrl(inputText);
navigator.clipboard.writeText(url);
generateCompressedNovelUrl(inputText).then((url) => {
navigator.clipboard.writeText(url);
});
}

if (isTauriApp()) {
Expand Down
104 changes: 104 additions & 0 deletions src/routes/utils/compression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();

const createUpstream = (value: unknown) => {
return new ReadableStream({
start(controller) {
controller.enqueue(value);
controller.close();
},
});
};

export async function compressToBase64(input: string): Promise<string> {
const upstream = createUpstream(textEncoder.encode(input));
const compression = new CompressionStream("deflate");
const stream = upstream.pipeThrough(compression);
const compressed = await new Response(stream).arrayBuffer();
return btoa(
new Uint8Array(compressed).reduce(
(acc, c) => acc + String.fromCharCode(c),
"",
),
);
}

export async function decompressFromBase64(input: string): Promise<string> {
const compressedBytes = Uint8Array.from(atob(input), (c) => c.charCodeAt(0));
const upstream = createUpstream(compressedBytes);
const decompression = new DecompressionStream("deflate");
const stream = upstream.pipeThrough(decompression);
const decompressed = await new Response(stream).arrayBuffer();
return textDecoder.decode(decompressed);
}

export async function compressToUTF16(input: string): Promise<string> {
const upstream = createUpstream(textEncoder.encode(input));
const compression = new CompressionStream("deflate");
const stream = upstream.pipeThrough(compression);
const compressed = await new Response(stream).arrayBuffer();

let compressedBytes = new Uint8Array(compressed);

if (compressedBytes.length % 2 !== 0) {
const paddedBytes = new Uint8Array(compressedBytes.length + 1);
paddedBytes.set(compressedBytes);
paddedBytes[compressedBytes.length] = 0; // 奇数個配列の場合、最後のバイトに 0 をパディング
compressedBytes = paddedBytes;
}

const compressedUint16Array = new Uint16Array(compressedBytes.buffer);
return String.fromCharCode(...compressedUint16Array);
}

export async function decompressFromUTF16(input: string): Promise<string> {
const compressedUint16Array = new Uint16Array(
input.split("").map((c) => c.charCodeAt(0)),
);
let compressedBytes = new Uint8Array(compressedUint16Array.buffer);

if (compressedBytes[compressedBytes.length - 1] === 0) {
compressedBytes = compressedBytes.slice(0, compressedBytes.length - 1); // パディングされた 0 を削除
}

const upstream = createUpstream(compressedBytes);
const decompression = new DecompressionStream("deflate");
const stream = upstream.pipeThrough(decompression);
const decompressed = await new Response(stream).arrayBuffer();
return textDecoder.decode(decompressed);
}

export async function compressToUint8Array(input: string): Promise<Uint8Array> {
const upstream = createUpstream(textEncoder.encode(input));
const compression = new CompressionStream("deflate");
const stream = upstream.pipeThrough(compression);
const compressed = await new Response(stream).arrayBuffer();
return new Uint8Array(compressed);
}

export async function decompressFromUint8Array(
input: Uint8Array,
): Promise<string> {
const upstream = createUpstream(input);
const decompression = new DecompressionStream("deflate");
const stream = upstream.pipeThrough(decompression);
const decompressed = await new Response(stream).arrayBuffer();
return textDecoder.decode(decompressed);
}

export async function compressToEncodedURIComponent(
input: string,
): Promise<string> {
const withBase64 = await compressToBase64(input);
return withBase64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

export async function decompressFromEncodedURIComponent(
input: string,
): Promise<string> {
let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
while (base64.length % 4) {
base64 += "=";
}
return decompressFromBase64(base64);
}
13 changes: 9 additions & 4 deletions src/routes/utils/generate-compressed-novel-url.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { page } from "$app/stores";
import { compressToEncodedURIComponent } from "lz-string";
import { compressToEncodedURIComponent } from "./compression";
import { get } from "svelte/store";

export function generateCompressedNovelUrl(text: string): string {
const compressedText = compressToEncodedURIComponent(text);
return `${get(page).url.origin}?novel=${compressedText}`;
export async function generateCompressedNovelUrl(
text: string,
): Promise<string> {
const compressedText = await compressToEncodedURIComponent(text);
console.log(compressedText);
const url = `${get(page).url.origin}?novel=${compressedText}`;
console.log(url);
return url;
}
15 changes: 8 additions & 7 deletions src/routes/utils/generate-search-params-to-text.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { decompressFromEncodedURIComponent } from "lz-string";
import { decompressFromEncodedURIComponent } from "./compression";

export function generateSearchParamsToText(
export async function generateSearchParamsToText(
urlSearchParams: URLSearchParams,
): string | null {
): Promise<string> {
const compressedText = urlSearchParams.get("novel");
if (!compressedText) return null; // undefinedの代わりにnullを返す
if (!compressedText) {
return "";
}

const result: string = decompressFromEncodedURIComponent(compressedText);

return result || null;
const result = decompressFromEncodedURIComponent(compressedText);
return result ?? ""; // resultがnullの場合は空文字を返す
}
Loading