refactor: migrate unplugin-live2d-sdk & unplugin-download to https://github.com/proj-airi

This commit is contained in:
Neko Ayaka
2025-03-15 23:24:41 +08:00
parent 7cbc8d567d
commit 71f9b4af1b
15 changed files with 55 additions and 441 deletions
+2 -2
View File
@@ -105,8 +105,8 @@
"@proj-airi/lobe-icons": "^0.3.6",
"@proj-airi/provider-transformers": "workspace:^",
"@proj-airi/ui-transitions": "workspace:^",
"@proj-airi/unplugin-download": "workspace:^",
"@proj-airi/unplugin-live2d-sdk": "workspace:^",
"@proj-airi/unplugin-fetch": "^0.1.4",
"@proj-airi/unplugin-live2d-sdk": "^0.1.2",
"@shikijs/markdown-it": "^3.2.1",
"@types/culori": "^2.1.1",
"@types/markdown-it-link-attributes": "^3.0.5",
+2 -2
View File
@@ -101,8 +101,8 @@
"@proj-airi/lobe-icons": "^0.3.6",
"@proj-airi/provider-transformers": "workspace:^",
"@proj-airi/ui-transitions": "workspace:^",
"@proj-airi/unplugin-download": "workspace:^",
"@proj-airi/unplugin-live2d-sdk": "workspace:^",
"@proj-airi/unplugin-fetch": "^0.1.4",
"@proj-airi/unplugin-live2d-sdk": "^0.1.2",
"@shikijs/markdown-it": "^3.2.1",
"@types/culori": "^2.1.1",
"@types/markdown-it-link-attributes": "^3.0.5",
-46
View File
@@ -1,46 +0,0 @@
{
"name": "@proj-airi/unplugin-download",
"type": "module",
"private": true,
"description": "Vite plugin to download files",
"author": {
"name": "Neko Ayaka",
"email": "neko@ayaka.moe",
"url": "https://github.com/nekomeowww"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/moeru-ai/airi.git",
"directory": "packages/unplugin-download"
},
"exports": {
".": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"require": "./dist/vite/index.cjs"
},
"./vite": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"node": "./dist/vite/index.cjs"
}
},
"main": "./dist/vite/index.cjs",
"module": "./dist/vite/index.mjs",
"types": "./dist/vite/index.d.ts",
"files": [
"README.md",
"dist",
"package.json"
],
"scripts": {
"dev": "pnpm run stub",
"stub": "unbuild --stub",
"build": "unbuild"
},
"dependencies": {
"ofetch": "^1.4.1",
"vite": "^6.2.2"
}
}
@@ -1,25 +0,0 @@
import { stat } from 'node:fs/promises'
export async function exists(path: string) {
try {
await stat(path)
return true
}
catch (error) {
if (isENOENTError(error))
return false
throw error
}
}
export function isENOENTError(error: unknown): boolean {
if (!(error instanceof Error))
return false
if (!('code' in error))
return false
if (error.code !== 'ENOENT')
return false
return true
}
@@ -1 +0,0 @@
export * from './fs'
@@ -1,52 +0,0 @@
import type { Plugin } from 'vite'
import { Buffer } from 'node:buffer'
import { copyFile, mkdir, writeFile } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { ofetch } from 'ofetch'
import { createLogger } from 'vite'
import { exists } from '../utils'
export function Download(
url: string,
filename: string,
destination: string,
): Plugin {
return {
name: `download-${filename}`,
async configResolved(config) {
const logger = createLogger()
const cacheDir = resolve(join(config.root, '.cache'))
const publicDir = resolve(join(config.root, 'public'))
try {
// cache
if (await exists(resolve(join(cacheDir, destination, filename)))) {
return
}
logger.info(`Downloading ${filename}...`)
const stream = await ofetch(url, { responseType: 'arrayBuffer' })
await mkdir(join(cacheDir, destination), { recursive: true })
await writeFile(join(cacheDir, destination, filename), Buffer.from(stream))
logger.info(`${filename} downloaded.`)
if (await exists(resolve(join(publicDir, destination, filename)))) {
return
}
await mkdir(join(publicDir, destination), { recursive: true }).catch(() => { })
await copyFile(join(cacheDir, destination, filename), join(publicDir, destination, filename))
// TODO: use motion editor to remap emotions
}
catch (err) {
console.error(err)
throw err
}
},
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": [
"ESNext"
],
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
]
}
-47
View File
@@ -1,47 +0,0 @@
{
"name": "@proj-airi/unplugin-live2d-sdk",
"type": "module",
"private": true,
"description": "Vite plugin to download Live2D SDK",
"author": {
"name": "Neko Ayaka",
"email": "neko@ayaka.moe",
"url": "https://github.com/nekomeowww"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/moeru-ai/airi.git",
"directory": "packages/unplugin-live2d-sdk"
},
"exports": {
".": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"require": "./dist/vite/index.cjs"
},
"./vite": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"node": "./dist/vite/index.cjs"
}
},
"main": "./dist/vite/index.cjs",
"module": "./dist/vite/index.mjs",
"types": "./dist/vite/index.d.ts",
"files": [
"README.md",
"dist",
"package.json"
],
"scripts": {
"dev": "pnpm run stub",
"stub": "unbuild --stub",
"build": "unbuild"
},
"dependencies": {
"ofetch": "^1.4.1",
"vite": "^6.2.2",
"yauzl": "^3.2.0"
}
}
@@ -1,38 +0,0 @@
export function rejectIfError<E = unknown>(error: E | undefined, reject: (error?: E) => void, handler?: (error?: E) => void) {
if (error) {
reject(error)
!!handler && handler(error)
}
}
export function resolveWhenNoError<R = void, E = unknown>(reject: (error?: E) => void, resolve: (result?: R) => void) {
return (err?: E) => {
if (err) {
reject(err)
}
else {
resolve()
}
}
}
export function onError<E = unknown>(reject: (error?: E) => void, handler?: (error?: E) => void) {
return (error?: E) => rejectIfError(error, reject, handler)
}
export function noError<
T,
U extends unknown[],
E = unknown,
>(
reject: (err?: E) => void,
fn: (...args: U) => T,
): (err: E | undefined, ...args: U) => T | undefined {
return (err, ...args) => {
if (err) {
rejectIfError(err, reject)
return
}
return fn(...args)
}
}
@@ -1,25 +0,0 @@
import { stat } from 'node:fs/promises'
export async function exists(path: string) {
try {
await stat(path)
return true
}
catch (error) {
if (isENOENTError(error))
return false
throw error
}
}
export function isENOENTError(error: unknown): boolean {
if (!(error instanceof Error))
return false
if (!('code' in error))
return false
if (error.code !== 'ENOENT')
return false
return true
}
@@ -1,3 +0,0 @@
export * from './errors'
export * from './fs'
export * from './unzip'
@@ -1,89 +0,0 @@
import type { Buffer } from 'node:buffer'
import { createWriteStream, existsSync, mkdirSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fromBuffer } from 'yauzl'
import { noError, onError } from './errors'
/**
* Example:
*
* await unzip("./tim.zip", "./");
*
* Will create directories:
*
* ./tim.zip
* ./tim
*
* Originally by [How to unzip to a folder using yauzl? - Stack Overflow](https://stackoverflow.com/questions/63932027/how-to-unzip-to-a-folder-using-yauzl)
*
* @param buffer Buffer of the zip file.
* @param target Path to the folder where the zip folder will be put.
*/
export async function unzip(buffer: Buffer, target: string) {
return new Promise<void>((resolve, reject) => {
let pendingWrites = 0
let isReadingComplete = false
function tryResolve() {
if (isReadingComplete && pendingWrites === 0) {
resolve()
}
}
fromBuffer(buffer, { lazyEntries: true }, noError(reject, (zipFile) => {
// This is the key. We start by reading the first entry.
zipFile.readEntry()
// Now for every entry, we will write a file or dir
// to disk. Then call zipFile.readEntry() again to
// trigger the next cycle.
zipFile.on('entry', (entry) => {
// Directories
if (/\/$/.test(entry.fileName)) {
// Create the directory then read the next entry.
mkdirSync(join(target, entry.fileName), { recursive: true })
zipFile.readEntry()
return
}
// Files
const dir = dirname(join(target, entry.fileName))
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true })
}
// Write the file to disk.
pendingWrites++
zipFile.openReadStream(entry, noError(reject, (readStream) => {
const file = createWriteStream(join(target, entry.fileName))
readStream.pipe(file)
// Handle errors
file.on('error', (err) => {
pendingWrites--
zipFile.close()
reject(err)
})
// Wait until the file is finished writing, then read the next entry.
file.on('finish', () => {
file.close(() => {
pendingWrites--
tryResolve()
zipFile.readEntry()
})
})
}))
})
zipFile.on('error', onError(reject, zipFile.close))
zipFile.on('end', noError(reject, () => {
isReadingComplete = true
tryResolve()
}))
}))
})
}
@@ -1,44 +0,0 @@
import type { Plugin } from 'vite'
import { Buffer } from 'node:buffer'
import { copyFile, mkdir } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { ofetch } from 'ofetch'
import { createLogger } from 'vite'
import { exists, unzip } from '../utils'
export function DownloadLive2DSDK(): Plugin {
return {
name: `download-live2d-cubism-sdk`,
async configResolved(config) {
const logger = createLogger()
const cacheDir = resolve(join(config.root, '.cache'))
const publicDir = resolve(join(config.root, 'public'))
try {
// cache
if (!(await exists(resolve(join(cacheDir, 'assets/js/CubismSdkForWeb-5-r.1'))))) {
logger.info('Downloading Cubism SDK...')
const stream = await ofetch('https://dist.ayaka.moe/npm/live2d-cubism/CubismSdkForWeb-5-r.1.zip', { responseType: 'arrayBuffer' })
logger.info('Unzipping Cubism SDK...')
await mkdir(join(cacheDir, 'assets/js'), { recursive: true })
await unzip(Buffer.from(stream), join(cacheDir, 'assets/js'))
logger.info('Cubism SDK downloaded and unzipped.')
}
if (!(await exists(resolve(join(publicDir, 'assets/js/CubismSdkForWeb-5-r.1'))))) {
await mkdir(join(publicDir, 'assets/js/CubismSdkForWeb-5-r.1/Core'), { recursive: true }).catch(() => {})
await copyFile(join(cacheDir, 'assets/js/CubismSdkForWeb-5-r.1/Core/live2dcubismcore.min.js'), join(publicDir, 'assets/js/CubismSdkForWeb-5-r.1/Core/live2dcubismcore.min.js'))
}
}
catch (err) {
console.error(err)
throw err
}
},
}
}
@@ -1,18 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": [
"ESNext"
],
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
]
}
+51 -31
View File
@@ -385,12 +385,12 @@ importers:
'@proj-airi/ui-transitions':
specifier: workspace:^
version: link:../../packages/ui-transitions
'@proj-airi/unplugin-download':
specifier: workspace:^
version: link:../../packages/unplugin-download
'@proj-airi/unplugin-fetch':
specifier: ^0.1.4
version: 0.1.4(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
'@proj-airi/unplugin-live2d-sdk':
specifier: workspace:^
version: link:../../packages/unplugin-live2d-sdk
specifier: ^0.1.2
version: 0.1.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
'@shikijs/markdown-it':
specifier: ^3.2.1
version: 3.2.1
@@ -719,12 +719,12 @@ importers:
'@proj-airi/ui-transitions':
specifier: workspace:^
version: link:../../packages/ui-transitions
'@proj-airi/unplugin-download':
specifier: workspace:^
version: link:../../packages/unplugin-download
'@proj-airi/unplugin-fetch':
specifier: ^0.1.4
version: 0.1.4(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
'@proj-airi/unplugin-live2d-sdk':
specifier: workspace:^
version: link:../../packages/unplugin-live2d-sdk
specifier: ^0.1.2
version: 0.1.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
'@shikijs/markdown-it':
specifier: ^3.2.1
version: 3.2.1
@@ -1112,27 +1112,6 @@ importers:
specifier: ^2.2.8
version: 2.2.8(typescript@5.8.2)
packages/unplugin-download:
dependencies:
ofetch:
specifier: ^1.4.1
version: 1.4.1
vite:
specifier: ^6.2.2
version: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
packages/unplugin-live2d-sdk:
dependencies:
ofetch:
specifier: ^1.4.1
version: 1.4.1
vite:
specifier: ^6.2.2
version: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
yauzl:
specifier: ^3.2.0
version: 3.2.0
packages/utils-transformers:
dependencies:
'@huggingface/transformers':
@@ -4069,6 +4048,12 @@ packages:
'@proj-airi/server-shared@0.3.6':
resolution: {integrity: sha512-VVGhVHDrZojH2RQIC6w4znmA/QlWrxFL3UI1N/pQU20vpRN23r4NaG/XvxdlzxQOYuXkyHvdc6/gn1b+qJnBpA==}
'@proj-airi/unplugin-fetch@0.1.4':
resolution: {integrity: sha512-COL9bzbT9wNv+yyueIvC6tcd3EuiAHMuMGpZNJlCn1qsThpi5mIvak2KZH5HYiDo7wusDVLBnye1fG92r1hYTA==}
'@proj-airi/unplugin-live2d-sdk@0.1.2':
resolution: {integrity: sha512-zmpjfQ64le+NTzWrM7eXIVUtSicsyYDuJeYBXPK8Z0eW3S7oMoGHrlcm0oPqPROpRoem4PHgHLhB6T1LLQqitw==}
'@protobufjs/aspromise@1.1.2':
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
@@ -14591,6 +14576,41 @@ snapshots:
dependencies:
crossws: 0.3.4
'@proj-airi/unplugin-fetch@0.1.4(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)':
dependencies:
ofetch: 1.4.1
vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- terser
- tsx
- yaml
'@proj-airi/unplugin-live2d-sdk@0.1.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)':
dependencies:
ofetch: 1.4.1
vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.17.6)(tsx@4.19.3)(yaml@2.7.0)
yauzl: 3.2.0
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- terser
- tsx
- yaml
'@protobufjs/aspromise@1.1.2': {}
'@protobufjs/base64@1.1.2': {}