mirror of
https://github.com/patarapolw/cjdic2.git
synced 2026-11-09 17:39:35 +00:00
add supabase file server and downloader
This commit is contained in:
1 parent
cbef2046fd
commit
811dd73e13
8 files changed
+223
-3
No files matched your search
@@ -13,6 +13,7 @@
|
||||
"dependencies": {
|
||||
"@fastify/mongodb": "^10.0.0",
|
||||
"@fastify/static": "^9.0.0",
|
||||
"@supabase/supabase-js": "^2.98.0",
|
||||
"adm-zip": "^0.5.16",
|
||||
"dotenv": "^17.3.1",
|
||||
"fastify": "^5.7.4",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import "dotenv/config";
|
||||
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabaseUrl = process.env.VITE_SUPABASE_URL!;
|
||||
const supabasePublishableKey = process.env.VITE_SUPABASE_PUBLISHABLE_KEY!;
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabasePublishableKey);
|
||||
|
||||
async function main() {
|
||||
const { data, error } = await supabase.storage.from("yomitan").list("ja");
|
||||
if (error) throw error;
|
||||
if (data) {
|
||||
console.log(data.map((d) => d.id));
|
||||
|
||||
const toDownload = data.filter(() => true);
|
||||
|
||||
console.log(
|
||||
toDownload.map((d) =>
|
||||
supabase.storage.from("yomitan").getPublicUrl(`ja/${d.name}`),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
Generated
+100
@@ -20,6 +20,9 @@ importers:
|
||||
'@fastify/static':
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
'@supabase/supabase-js':
|
||||
specifier: ^2.98.0
|
||||
version: 2.98.0
|
||||
adm-zip:
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.16
|
||||
@@ -54,6 +57,9 @@ importers:
|
||||
'@emotion/react':
|
||||
specifier: ^11.14.0
|
||||
version: 11.14.0(@types/react@19.2.14)(react@19.2.4)
|
||||
'@supabase/supabase-js':
|
||||
specifier: ^2.98.0
|
||||
version: 2.98.0
|
||||
'@tauri-apps/api':
|
||||
specifier: ^2
|
||||
version: 2.10.1
|
||||
@@ -618,6 +624,30 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@supabase/auth-js@2.98.0':
|
||||
resolution: {integrity: sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/functions-js@2.98.0':
|
||||
resolution: {integrity: sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/postgrest-js@2.98.0':
|
||||
resolution: {integrity: sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/realtime-js@2.98.0':
|
||||
resolution: {integrity: sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/storage-js@2.98.0':
|
||||
resolution: {integrity: sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/supabase-js@2.98.0':
|
||||
resolution: {integrity: sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@swc/helpers@0.5.18':
|
||||
resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==}
|
||||
|
||||
@@ -733,6 +763,9 @@ packages:
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
|
||||
'@types/phoenix@1.6.7':
|
||||
resolution: {integrity: sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==}
|
||||
|
||||
'@types/react-dom@19.2.3':
|
||||
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
|
||||
peerDependencies:
|
||||
@@ -747,6 +780,9 @@ packages:
|
||||
'@types/whatwg-url@13.0.0':
|
||||
resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||
|
||||
'@vitejs/plugin-react@4.7.0':
|
||||
resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -1174,6 +1210,10 @@ packages:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
iceberg-js@0.8.1:
|
||||
resolution: {integrity: sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -1568,6 +1608,18 @@ packages:
|
||||
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
ws@8.19.0:
|
||||
resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
|
||||
@@ -2118,6 +2170,44 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.58.0':
|
||||
optional: true
|
||||
|
||||
'@supabase/auth-js@2.98.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/functions-js@2.98.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/postgrest-js@2.98.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/realtime-js@2.98.0':
|
||||
dependencies:
|
||||
'@types/phoenix': 1.6.7
|
||||
'@types/ws': 8.18.1
|
||||
tslib: 2.8.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@supabase/storage-js@2.98.0':
|
||||
dependencies:
|
||||
iceberg-js: 0.8.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/supabase-js@2.98.0':
|
||||
dependencies:
|
||||
'@supabase/auth-js': 2.98.0
|
||||
'@supabase/functions-js': 2.98.0
|
||||
'@supabase/postgrest-js': 2.98.0
|
||||
'@supabase/realtime-js': 2.98.0
|
||||
'@supabase/storage-js': 2.98.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@swc/helpers@0.5.18':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -2216,6 +2306,8 @@ snapshots:
|
||||
|
||||
'@types/parse-json@4.0.2': {}
|
||||
|
||||
'@types/phoenix@1.6.7': {}
|
||||
|
||||
'@types/react-dom@19.2.3(@types/react@19.2.14)':
|
||||
dependencies:
|
||||
'@types/react': 19.2.14
|
||||
@@ -2230,6 +2322,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/webidl-conversions': 7.0.3
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 24.10.13
|
||||
|
||||
'@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@24.10.13)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
@@ -3005,6 +3101,8 @@ snapshots:
|
||||
statuses: 2.0.2
|
||||
toidentifier: 1.0.1
|
||||
|
||||
iceberg-js@0.8.1: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
@@ -3312,6 +3410,8 @@ snapshots:
|
||||
tr46: 5.1.1
|
||||
webidl-conversions: 7.0.0
|
||||
|
||||
ws@8.19.0: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yaml@1.10.2: {}
|
||||
|
||||
@@ -82,7 +82,7 @@ impl AppService {
|
||||
rusqlite::types::ValueRef::Text(t) => {
|
||||
serde_json::Value::String(String::from_utf8_lossy(t).into())
|
||||
}
|
||||
_ => serde_json::Value::Null,
|
||||
rusqlite::types::ValueRef::Blob(_) => serde_json::Value::Null,
|
||||
};
|
||||
obj.insert(name.clone(), value);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@chakra-ui/react": "^3.33.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@supabase/supabase-js": "^2.98.0",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-fs": "~2.4.5",
|
||||
"@tauri-apps/plugin-http": "~2.5.7",
|
||||
|
||||
@@ -3,6 +3,14 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { Dialog, Portal } from "@chakra-ui/react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import {
|
||||
BaseDirectory,
|
||||
exists,
|
||||
readDir,
|
||||
writeFile,
|
||||
} from "@tauri-apps/plugin-fs";
|
||||
|
||||
import { supabase } from "../lib/supabaseClient";
|
||||
|
||||
interface LoadYomitanZipDirResult {
|
||||
new_dicts: string[];
|
||||
@@ -31,7 +39,26 @@ function LoadingDialog() {
|
||||
if (isInit.current) return;
|
||||
isInit.current = true;
|
||||
|
||||
invoke("init_yomitan").then(() => {
|
||||
invoke("init_yomitan").then(async () => {
|
||||
const { data, error } = await supabase.storage.from("yomitan").list("ja");
|
||||
if (error) throw error;
|
||||
|
||||
for (const d of data || []) {
|
||||
const filepath = `yomitan/ja/${d.name}`;
|
||||
if (
|
||||
await exists(filepath, {
|
||||
baseDir: BaseDirectory.AppData,
|
||||
})
|
||||
)
|
||||
continue;
|
||||
|
||||
const {
|
||||
data: { publicUrl },
|
||||
} = supabase.storage.from("yomitan").getPublicUrl(`ja/${d.name}`);
|
||||
|
||||
// await downloadURL(publicUrl, filepath, (received, total) => {});
|
||||
}
|
||||
|
||||
setMessages([]);
|
||||
});
|
||||
|
||||
@@ -105,3 +132,49 @@ function LoadingDialog() {
|
||||
}
|
||||
|
||||
export default LoadingDialog;
|
||||
|
||||
async function downloadURL(
|
||||
url: string,
|
||||
filepath: string,
|
||||
progressCallback: (received: number, total: number) => void,
|
||||
) {
|
||||
const r = await fetch(url);
|
||||
if (!r.ok) throw r;
|
||||
if (!r.body) throw r;
|
||||
|
||||
const contentLength = r.headers.get("Content-Length");
|
||||
const total = contentLength ? parseInt(contentLength) : 0;
|
||||
|
||||
let receivedBytes = 0;
|
||||
|
||||
const reader = r.body.getReader();
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
function push() {
|
||||
reader
|
||||
.read()
|
||||
.then(({ done, value }) => {
|
||||
if (done) {
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
receivedBytes += value.length;
|
||||
|
||||
// Calculate and log progress
|
||||
if (total) progressCallback(receivedBytes, total);
|
||||
|
||||
controller.enqueue(value);
|
||||
push(); // Read the next chunk
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Stream reading error:", error);
|
||||
controller.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
push(); // Start reading the data
|
||||
},
|
||||
});
|
||||
|
||||
await writeFile(filepath, stream, { baseDir: BaseDirectory.AppData });
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
|
||||
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY;
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabasePublishableKey);
|
||||
@@ -16,6 +16,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"fs:default"
|
||||
"fs:allow-exists",
|
||||
"fs:allow-appdata-write",
|
||||
"fs:allow-appdata-meta",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [
|
||||
"$APPDATA/**/*.zip"
|
||||
],
|
||||
"deny": [
|
||||
"$APPDATA/*.db"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user