mirror of
https://github.com/moeru-ai/airi.git
synced 2026-08-14 08:52:42 +00:00
feat: automation for models downloading
This commit is contained in:
@@ -270,7 +270,7 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<div flex="~ row 1" w-full items-end space-x-2>
|
||||
<div w-full min-h="100 sm:100">
|
||||
<Live2DViewer ref="live2DViewerRef" :mouth-open-size="mouthOpenSize" model="assets/live2d/models/hiyori_pro_zh/hiyori_pro_t11.model3.json" />
|
||||
<Live2DViewer ref="live2DViewerRef" :mouth-open-size="mouthOpenSize" model="assets/live2d/models/hiyori_pro_zh/runtime/hiyori_pro_t11.model3.json" />
|
||||
<!-- <div>
|
||||
<input v-model.number="mouthOpenSize" type="range" max="1" min="0" step="0.01">
|
||||
<span>{{ mouthOpenSize }}</span>
|
||||
|
||||
@@ -23,5 +23,6 @@ words:
|
||||
- rehype
|
||||
- unocss
|
||||
- vueuse
|
||||
- live2dcubismcore
|
||||
ignoreWords: []
|
||||
import: []
|
||||
|
||||
+62
-10
@@ -43,7 +43,7 @@ export default defineNuxtConfig({
|
||||
prerender: {
|
||||
crawlLinks: false,
|
||||
routes: ['/'],
|
||||
ignore: ['/hi'],
|
||||
ignore: ['/assets/js/CubismSdkForWeb-5-r.1/Core/live2dcubismcore.min.js'],
|
||||
},
|
||||
experimental: {
|
||||
websocket: true,
|
||||
@@ -83,20 +83,72 @@ export default defineNuxtConfig({
|
||||
vite: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'live2d-cubism',
|
||||
name: 'live2d-cubism-sdk',
|
||||
async configResolved(config) {
|
||||
if (await exists(join(config.root, 'public/assets/js/CubismSdkForWeb-5-r.1'))) {
|
||||
return
|
||||
try {
|
||||
if (await exists(join(config.root, 'public/assets/js/CubismSdkForWeb-5-r.1'))) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Downloading Cubism SDK...')
|
||||
const stream = await ofetch('https://dist.ayaka.moe/npm/live2d-cubism/CubismSdkForWeb-5-r.1.zip', { responseType: 'arrayBuffer' })
|
||||
|
||||
console.log('Unzipping Cubism SDK...')
|
||||
await mkdir(join(config.root, 'public/assets/js'), { recursive: true })
|
||||
await unzip(Buffer.from(stream), join(config.root, 'public/assets/js'))
|
||||
|
||||
console.log('Cubism SDK downloaded and unzipped.')
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
throw err
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'live2d-models-hiyori-free',
|
||||
async configResolved(config) {
|
||||
try {
|
||||
if (await exists(join(config.root, 'public/assets/live2d/models/hiyori_free_zh'))) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Downloading Cubism SDK...')
|
||||
const stream = await ofetch('https://dist.ayaka.moe/npm/live2d-cubism/CubismSdkForWeb-5-r.1.zip', { responseType: 'arrayBuffer' })
|
||||
console.log('Downloading Demo Live2D Model - Hiyori Free...')
|
||||
const stream = await ofetch('https://dist.ayaka.moe/live2d-models/hiyori_free_zh.zip', { responseType: 'arrayBuffer' })
|
||||
|
||||
console.log('Unzipping Cubism SDK...')
|
||||
await mkdir(join(config.root, 'public/assets/js'), { recursive: true })
|
||||
await unzip(Buffer.from(stream), join(config.root, 'public/assets/js'))
|
||||
console.log('Unzipping Demo Live2D Model - Hiyori Free...')
|
||||
await mkdir(join(config.root, 'public/assets/live2d/models'), { recursive: true })
|
||||
await unzip(Buffer.from(stream), join(config.root, 'public/assets/live2d/models'))
|
||||
|
||||
console.log('Cubism SDK downloaded and unzipped.')
|
||||
console.log('Demo Live2D Model - Hiyori Free downloaded and unzipped.')
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
throw err
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'live2d-models-hiyori-pro',
|
||||
async configResolved(config) {
|
||||
try {
|
||||
if (await exists(join(config.root, 'public/assets/live2d/models/hiyori_pro_zh'))) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Downloading Demo Live2D Model - Hiyori Pro...')
|
||||
const stream = await ofetch('https://dist.ayaka.moe/live2d-models/hiyori_pro_zh.zip', { responseType: 'arrayBuffer' })
|
||||
|
||||
console.log('Unzipping Demo Live2D Model - Hiyori Pro...')
|
||||
await mkdir(join(config.root, 'public/assets/live2d/models'), { recursive: true })
|
||||
await unzip(Buffer.from(stream), join(config.root, 'public/assets/live2d/models'))
|
||||
|
||||
console.log('Demo Live2D Model - Hiyori Pro downloaded and unzipped.')
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
throw err
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
+5
-6
@@ -5,12 +5,8 @@ export function rejectIfError<E = unknown>(error: E | undefined, reject: (error?
|
||||
}
|
||||
}
|
||||
|
||||
export function onError<E = unknown>(reject: (error?: E) => void, handler?: (error?: E) => void) {
|
||||
return (error?: E) => rejectIfError(error, reject, handler)
|
||||
}
|
||||
|
||||
export function resolveWhenNoError<R = void, E = unknown>(reject: (error?: E) => void, resolve: (result?: R) => void) {
|
||||
return (err: E) => {
|
||||
return (err?: E) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
}
|
||||
@@ -20,6 +16,10 @@ export function resolveWhenNoError<R = void, E = unknown>(reject: (error?: E) =>
|
||||
}
|
||||
}
|
||||
|
||||
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[],
|
||||
@@ -33,7 +33,6 @@ export function noError<
|
||||
rejectIfError(err, reject)
|
||||
return
|
||||
}
|
||||
|
||||
return fn(...args)
|
||||
}
|
||||
}
|
||||
|
||||
+14
-7
@@ -6,13 +6,20 @@ export async function exists(path: string) {
|
||||
return true
|
||||
}
|
||||
catch (error) {
|
||||
if (!(error instanceof Error))
|
||||
throw error
|
||||
if (!('code' in error))
|
||||
throw error
|
||||
if (error.code !== 'ENOENT')
|
||||
throw error
|
||||
if (isENOENTError(error))
|
||||
return false
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+28
-7
@@ -1,6 +1,6 @@
|
||||
import type { Buffer } from 'node:buffer'
|
||||
import { createWriteStream, mkdirSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { createWriteStream, existsSync, mkdirSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fromBuffer } from 'yauzl'
|
||||
import { noError, onError, resolveWhenNoError } from './errors'
|
||||
|
||||
@@ -21,6 +21,8 @@ import { noError, onError, resolveWhenNoError } from './errors'
|
||||
*/
|
||||
export async function unzip(buffer: Buffer, target: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let pendingWrites = 0
|
||||
|
||||
fromBuffer(buffer, { lazyEntries: true }, noError(reject, (zipFile) => {
|
||||
// This is the key. We start by reading the first entry.
|
||||
zipFile.readEntry()
|
||||
@@ -29,26 +31,45 @@ export async function unzip(buffer: Buffer, target: string) {
|
||||
// to disk. Then call zipFile.readEntry() again to
|
||||
// trigger the next cycle.
|
||||
zipFile.on('entry', (entry) => {
|
||||
// Directories
|
||||
// Directories
|
||||
if (/\/$/.test(entry.fileName)) {
|
||||
// Create the directory then read the next entry.
|
||||
mkdirSync(join(target, 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', onError(reject, zipFile.close))
|
||||
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(() => { zipFile.readEntry() }))
|
||||
file.on('finish', () => {
|
||||
file.close(() => {
|
||||
pendingWrites--
|
||||
if (pendingWrites === 0) {
|
||||
resolve()
|
||||
}
|
||||
|
||||
zipFile.readEntry()
|
||||
})
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user