feat: separate steam build and directory build to save space

This commit is contained in:
Haoyu Xu
2025-05-02 16:57:44 +08:00
parent 065fe5b15e
commit 093f9d7f1a
20 changed files with 503 additions and 373 deletions

View File

@@ -4,9 +4,9 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev:directory": "vite --clearScreen false", "dev:directory": "bunx --bun vite --clearScreen false",
"build": "mode=build bun runner.ts", "build:directory": "mode=build:directory bun runner.ts",
"preview:directory": "vite preview", "preview:directory": "bunx --bun vite preview",
"lint": "eslint && stylelint \"src/**/*.css\" \"src/**/*.scss\" && prettier --check ." "lint": "eslint && stylelint \"src/**/*.css\" \"src/**/*.scss\" && prettier --check ."
}, },
"dependencies": { "dependencies": {

View File

@@ -1,28 +1,12 @@
import path from 'node:path' import path from 'node:path'
import { DIST_DIR } from '@aklive2d/showcase' import { DIST_DIR } from '@aklive2d/showcase'
import { build as viteBuild } from 'vite' import { build as viteBuild } from 'vite'
import { envParser, file } from '@aklive2d/libs' import { file } from '@aklive2d/libs'
const build = async (namesToBuild: string[]) => { async function main() {
if (!namesToBuild.length) {
// skip as directory can only build
// when all operators are built
await viteBuild() await viteBuild()
const releaseDir = path.resolve(DIST_DIR) const releaseDir = path.resolve(DIST_DIR)
file.rmdir(releaseDir) file.rmdir(releaseDir)
} }
}
async function main() {
const { name } = envParser.parse({
name: {
type: 'string',
short: 'n',
multiple: true,
default: [],
},
})
await build(name as string[])
}
main() main()

View File

@@ -349,7 +349,7 @@ function OperatorElement({ item, hidden, handleVoicePlay }) {
<section <section
onMouseEnter={() => onMouseEnter={() =>
handleVoicePlay( handleVoicePlay(
`/${item.link}/assets/${buildConfig.voice_folders.main}/${buildConfig.app_voice_url}` `/${item.link}/${buildConfig.default_assets_dir}${buildConfig.voice_folders.main}/${buildConfig.app_voice_url}`
) )
} }
> >
@@ -439,7 +439,7 @@ function ImageElement({ item }) {
const { language } = useLanguage() const { language } = useLanguage()
return ( return (
<img <img
src={`/${buildConfig.directory_folder}/${item.fallback_name.replace(/#/g, '%23')}_portrait.png`} src={`/${buildConfig.directory_folder}/${buildConfig.portraits}/${item.fallback_name.replace(/#/g, '%23')}_portrait.png`}
alt={item.codename[language]} alt={item.codename[language]}
/> />
) )

View File

@@ -108,7 +108,9 @@ export default function Operator() {
if (spineRef.current?.children.length > 0) { if (spineRef.current?.children.length > 0) {
spineRef.current?.removeChild(spineRef.current?.children[0]) spineRef.current?.removeChild(spineRef.current?.children[0])
} }
fetch(`/${key}/assets/charword_table.json`) fetch(
`/${key}/${buildConfig.default_assets_dir}charword_table.json`
)
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
setVoiceConfig(data) setVoiceConfig(data)
@@ -159,7 +161,7 @@ export default function Operator() {
useEffect(() => { useEffect(() => {
if (spineRef.current?.children.length === 0 && configRef.current) { if (spineRef.current?.children.length === 0 && configRef.current) {
const playerConfig = { const playerConfig = {
atlasUrl: `./${key}/assets/${configRef.current.filename.replace(/#/g, '%23')}.atlas`, atlasUrl: `./${key}/${buildConfig.default_assets_dir}${configRef.current.filename.replace(/#/g, '%23')}.atlas`,
animation: spineAnimationName, animation: spineAnimationName,
premultipliedAlpha: true, premultipliedAlpha: true,
alpha: true, alpha: true,
@@ -200,7 +202,7 @@ export default function Operator() {
currentVoiceId = id currentVoiceId = id
setCurrentVoiceId(id) setCurrentVoiceId(id)
setVoiceSrc( setVoiceSrc(
`/${configRef.current.link}/assets/${getVoiceFoler(voiceLangRef.current)}/${id}.ogg` `/${configRef.current.link}/${buildConfig.default_assets_dir}${getVoiceFoler(voiceLangRef.current)}/${id}.ogg`
) )
lastVoiceId = currentVoiceId lastVoiceId = currentVoiceId
} }
@@ -208,9 +210,9 @@ export default function Operator() {
} }
if (configRef.current.use_json) { if (configRef.current.use_json) {
playerConfig.jsonUrl = `./${key}/assets/${configRef.current.filename.replace(/#/g, '%23')}.json` playerConfig.jsonUrl = `./${key}/${buildConfig.default_assets_dir}${configRef.current.filename.replace(/#/g, '%23')}.json`
} else { } else {
playerConfig.skelUrl = `./${key}/assets/${configRef.current.filename.replace(/#/g, '%23')}.skel` playerConfig.skelUrl = `./${key}/${buildConfig.default_assets_dir}${configRef.current.filename.replace(/#/g, '%23')}.skel`
} }
setSpinePlayer(new SpinePlayer(spineRef.current, playerConfig)) setSpinePlayer(new SpinePlayer(spineRef.current, playerConfig))
} }
@@ -267,7 +269,7 @@ export default function Operator() {
useEffect(() => { useEffect(() => {
if (voiceLang && isVoicePlaying) { if (voiceLang && isVoicePlaying) {
const audioUrl = `/assets/${getVoiceFoler(voiceLang)}/${currentVoiceId}.ogg` const audioUrl = `/${buildConfig.default_assets_dir}${getVoiceFoler(voiceLang)}/${currentVoiceId}.ogg`
if ( if (
voiceSrc !== voiceSrc !==
window.location.href.replace(/\/$/g, '') + audioUrl window.location.href.replace(/\/$/g, '') + audioUrl
@@ -287,7 +289,7 @@ export default function Operator() {
if (id) { if (id) {
setCurrentVoiceId(id) setCurrentVoiceId(id)
setVoiceSrc( setVoiceSrc(
`/${key}/assets/${getVoiceFoler(voiceLangRef.current)}/${id}.ogg` `/${key}/${buildConfig.default_assets_dir}${getVoiceFoler(voiceLangRef.current)}/${id}.ogg`
) )
} }
} }
@@ -563,13 +565,13 @@ export default function Operator() {
className={classes.container} className={classes.container}
style={ style={
currentBackground && { currentBackground && {
backgroundImage: `url(/chen/assets/${buildConfig.background_folder}/${currentBackground})`, backgroundImage: `url(/${buildConfig.directory_folder}/${buildConfig.background_folder}/${currentBackground})`,
} }
} }
> >
{config && ( {config && (
<img <img
src={`/${config.link}/assets/${config.logo}.png`} src={`/${buildConfig.directory_folder}/${buildConfig.logo_dir}${config.logo}.png`}
alt={config?.codename[language]} alt={config?.codename[language]}
className={classes.logo} className={classes.logo}
style={ style={
@@ -630,8 +632,8 @@ function MusicElement() {
useEffect(() => { useEffect(() => {
if (background && enableMusic) { if (background && enableMusic) {
const introOgg = musicMapping[background].intro const introOgg = musicMapping[background].intro
const intro = `./chen/assets/${buildConfig.music_folder}/${introOgg}` const intro = `/${buildConfig.directory_folder}/${buildConfig.music_folder}/${introOgg}`
const loop = `./chen/assets/${buildConfig.music_folder}/${musicMapping[background].loop}` const loop = `/${buildConfig.directory_folder}/${buildConfig.music_folder}/${musicMapping[background].loop}`
musicLoopRef.current.src = loop musicLoopRef.current.src = loop
if (introOgg) { if (introOgg) {
musicIntroRef.current.src = intro || loop musicIntroRef.current.src = intro || loop

View File

@@ -30,9 +30,9 @@ export default defineConfig(async () => {
), ),
rollupOptions: { rollupOptions: {
output: { output: {
entryFileNames: `${config.directory.assets_dir}/[name]-[hash:8].js`, entryFileNames: `${config.app.directory.assets}/[name].js`,
chunkFileNames: `${config.directory.assets_dir}/[name]-[hash:8].js`, chunkFileNames: `${config.app.directory.assets}/[name].js`,
assetFileNames: `${config.directory.assets_dir}/[name]-[hash:8].[ext]`, assetFileNames: `${config.app.directory.assets}/[name].[ext]`,
manualChunks: (id) => { manualChunks: (id) => {
if (id.includes('node_modules')) { if (id.includes('node_modules')) {
return 'vendor' // all other package goes here return 'vendor' // all other package goes here

View File

@@ -0,0 +1,35 @@
/**
* Adapted from 'spine-ts/core/src/Utils.ts'
*/
export class TimeKeeper {
framesPerSecond = 0
delta = 0
totalTime = 0
private lastTime = performance.now() / 1000
private frameCount = 0
private frameTime = 0
private fpsInterval = 1 / 60
update() {
const now = performance.now() / 1000
this.delta = now - this.lastTime
if (this.delta > this.fpsInterval) {
this.frameTime += this.delta
this.totalTime += this.delta
this.lastTime = now
this.frameCount++
if (this.frameTime > 1) {
this.framesPerSecond = this.frameCount / this.frameTime
this.frameTime = 0
this.frameCount = 0
}
} else {
this.delta = -1
}
}
setFps(v: number) {
this.fpsInterval = 1 / v
}
}

View File

@@ -1,4 +1,5 @@
import { spine } from '../spine-ts/build/spine-webgl.js' import { spine } from '../spine-ts/build/spine-webgl.js'
import { TimeKeeper } from './libs/TimeKeeper.ts'
/** /**
* Adapted from 'spine-ts/player/src/Player.ts' * Adapted from 'spine-ts/player/src/Player.ts'
@@ -104,15 +105,13 @@ export class Player {
private paused = false private paused = false
private playTime = 0 private playTime = 0
private speed = 1 private time = new TimeKeeper()
private time = new spine.TimeKeeper()
private currentViewport!: Viewport private currentViewport!: Viewport
private previousViewport!: Viewport private previousViewport!: Viewport
private viewportTransitionStart = 0 private viewportTransitionStart = 0
private parent: HTMLElement private parent: HTMLElement
private devicePixelRatio = window.devicePixelRatio || 1 private devicePixelRatio = window.devicePixelRatio || 1
private lastFrameTime: number = 0
private disposed = false private disposed = false
private eventListeners: { private eventListeners: {
target: HTMLElement | Document | Window target: HTMLElement | Document | Window
@@ -330,18 +329,17 @@ export class Player {
if (this.disposed) return if (this.disposed) return
if (requestNextFrame) requestAnimationFrame(() => this.drawFrame()) if (requestNextFrame) requestAnimationFrame(() => this.drawFrame())
this.time.update()
const delta = this.time.delta
if (delta !== -1) {
// Have we finished loading the asset? Then set things up // Have we finished loading the asset? Then set things up
if (this.assetManager.isLoadingComplete() && this.skeleton == null) if (this.assetManager.isLoadingComplete() && this.skeleton == null)
this.loadSkeleton() this.loadSkeleton()
// Resize the canvas // Resize the canvas
this.resize(spine.webgl.ResizeMode.Expand) this.resize(spine.webgl.ResizeMode.Expand)
// Update and draw the skeleton // Update and draw the skeleton
if (this.loaded) { if (this.loaded) {
const fpsInterval = 1 / this.config.fps
const now = performance.now() / 1000
// Update animation and skeleton based on user selections // Update animation and skeleton based on user selections
if (!this.paused && this.config.animation) { if (!this.paused && this.config.animation) {
const ctx = this.context const ctx = this.context
@@ -354,10 +352,6 @@ export class Player {
gl.clearColor(bg.r, bg.g, bg.b, bg.a) gl.clearColor(bg.r, bg.g, bg.b, bg.a)
gl.clear(gl.COLOR_BUFFER_BIT) gl.clear(gl.COLOR_BUFFER_BIT)
this.lastFrameTime = now
this.time.update()
const delta = this.time.delta * this.speed
const animationDuration = const animationDuration =
this.animationState.getCurrent(0).animation.duration this.animationState.getCurrent(0).animation.duration
this.playTime += delta this.playTime += delta
@@ -426,7 +420,8 @@ export class Player {
(viewport.y - oldViewport.y) * transitionAlpha, (viewport.y - oldViewport.y) * transitionAlpha,
width: width:
oldViewport.width + oldViewport.width +
(viewport.width - oldViewport.width) * transitionAlpha, (viewport.width - oldViewport.width) *
transitionAlpha,
height: height:
oldViewport.height + oldViewport.height +
(viewport.height - oldViewport.height) * (viewport.height - oldViewport.height) *
@@ -442,7 +437,8 @@ export class Player {
) )
this.sceneRenderer.camera.zoom = this.sceneRenderer.camera.zoom =
((viewport.width * this.devicePixelRatio) / viewportSize.x) * ((viewport.width * this.devicePixelRatio) /
viewportSize.x) *
this.scale this.scale
this.sceneRenderer.camera.position.x = this.sceneRenderer.camera.position.x =
viewport.x + viewport.width / 2 viewport.x + viewport.width / 2
@@ -462,6 +458,7 @@ export class Player {
this.sceneRenderer.camera.zoom = 0 this.sceneRenderer.camera.zoom = 0
} }
} }
}
private scaleViewport( private scaleViewport(
sourceWidth: number, sourceWidth: number,
@@ -621,7 +618,6 @@ export class Player {
} }
this.config.success(this) this.config.success(this)
this.lastFrameTime = performance.now() / 1000
this.loaded = true this.loaded = true
} }
@@ -847,6 +843,7 @@ export class Player {
set fps(v) { set fps(v) {
this.config.fps = v this.config.fps = v
this.time.setFps(v)
} }
} }

View File

@@ -5,9 +5,10 @@
"type": "module", "type": "module",
"main": "index.ts", "main": "index.ts",
"scripts": { "scripts": {
"dev:showcase": "vite --clearScreen false", "dev:showcase": "bunx --bun vite --clearScreen false",
"build": "mode=build bun runner.ts", "build": "mode=build bun runner.ts",
"preview:showcase": "vite preview", "build:directory": "mode=build:directory bun runner.ts",
"preview:showcase": "bunx --bun vite preview",
"lint": "eslint && prettier --check ." "lint": "eslint && prettier --check ."
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -5,34 +5,41 @@ import { envParser, file } from '@aklive2d/libs'
import { copyShowcaseData, copyProjectJSON } from '@aklive2d/vite-helpers' import { copyShowcaseData, copyProjectJSON } from '@aklive2d/vite-helpers'
import * as dirs from './index.js' import * as dirs from './index.js'
const build = async (namesToBuild: string[]) => { const build = async (namesToBuild: string[], mode: string) => {
const names = !namesToBuild.length ? Object.keys(operators) : namesToBuild const names = !namesToBuild.length ? Object.keys(operators) : namesToBuild
console.log('Generating assets for', names.length, 'operators') console.log('Generating assets for', names.length, 'operators')
for (const name of names) { for (const name of names) {
copyShowcaseData(name, { copyShowcaseData(name, {
dataDir: dirs.DATA_DIR, dataDir: dirs.DATA_DIR,
publicAssetsDir: dirs.PUBLIC_ASSETS_DIR, publicAssetsDir: dirs.PUBLIC_ASSETS_DIR,
mode,
}) })
await viteBuild() await viteBuild()
const releaseDir = path.join(dirs.DIST_DIR, name) const releaseDir = path.join(dirs.DIST_DIR, name)
file.mv(dirs.OUT_DIR, releaseDir) file.mv(dirs.OUT_DIR, releaseDir)
file.rm(dirs.DATA_DIR) file.rm(dirs.DATA_DIR)
if (mode !== 'build:directory') {
copyProjectJSON(name, { copyProjectJSON(name, {
releaseDir, releaseDir,
}) })
} }
} }
}
async function main() { async function main() {
const { name } = envParser.parse({ const { name, mode } = envParser.parse({
name: { name: {
type: 'string', type: 'string',
short: 'n', short: 'n',
multiple: true, multiple: true,
default: [], default: [],
}, },
mode: {
type: 'string',
short: 'm',
},
}) })
await build(name as string[]) await build(name as string[], mode as string)
} }
main() main()

View File

@@ -13,7 +13,7 @@ export default class Background {
#parentEl #parentEl
#videoEl #videoEl
#default = { #default = {
location: `${import.meta.env.BASE_URL}assets/${buildConfig.background_folder}/`, location: `${import.meta.env.BASE_URL}${buildConfig.build_assets_dir}${buildConfig.background_folder}/`,
image: buildConfig.default_background, image: buildConfig.default_background,
} }
#config = { #config = {

View File

@@ -30,7 +30,7 @@ export default class Fallback {
this.#el.innerHTML = ` this.#el.innerHTML = `
<div id="fallback-container"> <div id="fallback-container">
<div id="fallback" <div id="fallback"
style="background-image: url(./assets/${buildConfig.fallback_name}.png)" style="background-image: url(${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}${buildConfig.fallback_name}.png)"
/> />
</div> </div>
` `

View File

@@ -13,7 +13,7 @@ export default class Logo {
#imageEl #imageEl
#parentEl #parentEl
#default = { #default = {
location: `${import.meta.env.BASE_URL}assets/`, location: `${import.meta.env.BASE_URL}${buildConfig.build_assets_dir}${buildConfig.logo_dir}`,
image: `${buildConfig.logo_filename}.png`, image: `${buildConfig.logo_filename}.png`,
useInvertFilter: buildConfig.invert_filter, useInvertFilter: buildConfig.invert_filter,
ratio: 61.8, ratio: 61.8,

View File

@@ -104,8 +104,8 @@ export default class Music {
#playMusic() { #playMusic() {
if (!this.#config.name) { if (!this.#config.name) {
const introOgg = this.#music.mapping[this.#music.current].intro const introOgg = this.#music.mapping[this.#music.current].intro
const intro = `./assets/${this.#music.location}/${introOgg}` const intro = `${import.meta.env.BASE_URL}${buildConfig.build_assets_dir}${this.#music.location}/${introOgg}`
const loop = `./assets/${this.#music.location}/${this.#music.mapping[this.#music.current].loop}` const loop = `${import.meta.env.BASE_URL}${buildConfig.build_assets_dir}${this.#music.location}/${this.#music.mapping[this.#music.current].loop}`
this.#audio.loop.el.src = loop this.#audio.loop.el.src = loop
this.#audio.loop.el.querySelector('source').type = 'audio/ogg' this.#audio.loop.el.querySelector('source').type = 'audio/ogg'
if (introOgg) { if (introOgg) {

View File

@@ -45,7 +45,7 @@ export default class Player {
async init() { async init() {
const _this = this const _this = this
const playerConfig = { const playerConfig = {
atlasUrl: `./assets/${buildConfig.filename}.atlas`, atlasUrl: `${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}${buildConfig.filename}.atlas`,
premultipliedAlpha: true, premultipliedAlpha: true,
alpha: true, alpha: true,
backgroundColor: '#00000000', backgroundColor: '#00000000',
@@ -115,9 +115,9 @@ export default class Player {
}, },
} }
if (buildConfig.use_json) { if (buildConfig.use_json) {
playerConfig.jsonUrl = `./assets/${buildConfig.filename}.json` playerConfig.jsonUrl = `${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}${buildConfig.filename}.json`
} else { } else {
playerConfig.skelUrl = `./assets/${buildConfig.filename}.skel` playerConfig.skelUrl = `${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}${buildConfig.filename}.skel`
} }
this.#spine = new SpinePlayer(this.#el, playerConfig) this.#spine = new SpinePlayer(this.#el, playerConfig)
} }

View File

@@ -83,7 +83,9 @@ export default class Voice {
} }
async init() { async init() {
const res = await fetch('./assets/charword_table.json') const res = await fetch(
`${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}charword_table.json`
)
this.#charwordTable = await res.json() this.#charwordTable = await res.json()
this.#voice.languages = Object.keys( this.#voice.languages = Object.keys(
this.#charwordTable.voiceLangs[this.#default.region] this.#charwordTable.voiceLangs[this.#default.region]
@@ -170,7 +172,7 @@ export default class Voice {
if (!this.useVoice) return if (!this.useVoice) return
this.#voice.id.last = this.#voice.id.current this.#voice.id.last = this.#voice.id.current
this.#voice.id.current = id this.#voice.id.current = id
this.#audio.el.src = `./assets/${this.#getVoiceLocation()}/${id}.ogg` this.#audio.el.src = `${import.meta.env.BASE_URL}${buildConfig.default_assets_dir}${this.#getVoiceLocation()}/${id}.ogg`
let startPlayPromise = this.#audio.el.play() let startPlayPromise = this.#audio.el.play()
if (startPlayPromise !== undefined) { if (startPlayPromise !== undefined) {
startPlayPromise startPlayPromise

View File

@@ -11,6 +11,7 @@
"update": "turbo run update", "update": "turbo run update",
"init": "turbo run init", "init": "turbo run init",
"download:game": "turbo run download:game", "download:game": "turbo run download:game",
"build:directory": "turbo run build:directory",
"build:cleanup": "turbo run build:cleanup" "build:cleanup": "turbo run build:cleanup"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -50,6 +50,28 @@ app:
public: public public: public
assets: assets assets: assets
release: release release: release
directory:
assets: _assets
title: AKLive2D
voice: jp/CN_037.ogg
portraits: portraits
error:
files:
- key: build_char_128_plosis_epoque#3
paddings:
left: -120
right: 150
top: 10
bottom: 0
- key: build_char_128_plosis
paddings:
left: -90
right: 100
top: 10
bottom: 0
voice:
file: CN_034.ogg
target: error.ogg
dir_name: dir_name:
data: data data: data
dist: dist dist: dist
@@ -73,24 +95,3 @@ dir_name:
- name: custom - name: custom
lang: CUSTOM lang: CUSTOM
lookup_region: zh_CN lookup_region: zh_CN
directory:
assets_dir: _assets
title: AKLive2D
voice: jp/CN_037.ogg
error:
files:
- key: build_char_128_plosis_epoque#3
paddings:
left: -120
right: 150
top: 10
bottom: 0
- key: build_char_128_plosis
paddings:
left: -90
right: 100
top: 10
bottom: 0
voice:
file: CN_034.ogg
target: error.ogg

View File

@@ -65,25 +65,11 @@ export type Config = {
assets: string assets: string
release: string release: string
} }
}
dir_name: {
data: string
dist: string
extracted: string
auto_update: string
voice: {
main: string
sub: {
name: string
lang: string
lookup_region: string
}[]
}
}
directory: { directory: {
assets_dir: string assets: string
title: string title: string
voice: string voice: string
portraits: string
error: { error: {
files: { files: {
key: string key: string
@@ -101,3 +87,18 @@ export type Config = {
} }
} }
} }
dir_name: {
data: string
dist: string
extracted: string
auto_update: string
voice: {
main: string
sub: {
name: string
lang: string
lookup_region: string
}[]
}
}
}

View File

@@ -18,7 +18,11 @@ interface DirectoryOperatorConfig extends OperatorConfig {
export const copyShowcaseData = ( export const copyShowcaseData = (
name: string, name: string,
{ dataDir, publicAssetsDir }: { dataDir: string; publicAssetsDir: string } {
dataDir,
publicAssetsDir,
mode,
}: { dataDir: string; publicAssetsDir: string; mode: string }
) => { ) => {
file.mkdir(publicAssetsDir) file.mkdir(publicAssetsDir)
const operatorAssetsDir = path.join( const operatorAssetsDir = path.join(
@@ -40,11 +44,13 @@ export const copyShowcaseData = (
publicAssetsDir, publicAssetsDir,
config.module.assets.background config.module.assets.background
), ),
condition: mode !== 'build:directory',
}, },
{ {
fn: file.symlink, fn: file.symlink,
source: path.resolve(ASSETS_DIST_DIR, config.module.assets.music), source: path.resolve(ASSETS_DIST_DIR, config.module.assets.music),
target: path.resolve(publicAssetsDir, config.module.assets.music), target: path.resolve(publicAssetsDir, config.module.assets.music),
condition: mode !== 'build:directory',
}, },
{ {
fn: file.symlinkAll, fn: file.symlinkAll,
@@ -70,6 +76,7 @@ export const copyShowcaseData = (
filename: `${operators[name].logo}.png`, filename: `${operators[name].logo}.png`,
source: path.resolve(ASSETS_DIST_DIR, config.module.operator.logos), source: path.resolve(ASSETS_DIST_DIR, config.module.operator.logos),
target: path.resolve(publicAssetsDir), target: path.resolve(publicAssetsDir),
condition: mode !== 'build:directory',
}, },
{ {
fn: file.symlink, fn: file.symlink,
@@ -90,12 +97,14 @@ export const copyShowcaseData = (
target: path.resolve(publicAssetsDir), target: path.resolve(publicAssetsDir),
}) })
}) })
q.map(({ fn, filename, source, target }) => { q.map(({ fn, filename, source, target, condition = true }) => {
if (condition) {
if (filename) { if (filename) {
source = path.resolve(source, filename) source = path.resolve(source, filename)
target = path.resolve(target, filename) target = path.resolve(target, filename)
} }
fn(source, target) fn(source, target)
}
}) })
const buildConfig = { const buildConfig = {
insight_id: config.insight.id, insight_id: config.insight.id,
@@ -118,6 +127,15 @@ export const copyShowcaseData = (
music_folder: config.module.assets.music, music_folder: config.module.assets.music,
music_mapping: musicMapping.musicFileMapping, music_mapping: musicMapping.musicFileMapping,
use_json: operators[name].use_json, use_json: operators[name].use_json,
default_assets_dir: `${config.app.showcase.assets}/`,
logo_dir:
mode === 'build:directory'
? `${config.module.operator.logos}/`
: '',
build_assets_dir:
mode === 'build:directory'
? `../${config.app.directory.assets}/`
: `${config.app.showcase.assets}/`, // default is assets/, on build:directory mode is ../_assets
} }
file.writeSync( file.writeSync(
JSON.stringify(buildConfig), JSON.stringify(buildConfig),
@@ -165,9 +183,9 @@ export const copyDirectoryData = async ({
OPERATOR_SOURCE_FOLDER, OPERATOR_SOURCE_FOLDER,
config.module.operator.directory_assets config.module.operator.directory_assets
) )
const targetFolder = path.join(publicDir, config.directory.assets_dir) const targetFolder = path.join(publicDir, config.app.directory.assets)
const sourceFolder = path.join(ASSETS_DIST_DIR) const sourceFolder = path.join(ASSETS_DIST_DIR)
const filesToCopy = Object.keys(operators) const operatorFilesToCopy = Object.keys(operators)
const operatorConfig = Object.values( const operatorConfig = Object.values(
Object.values(operators).reduce( Object.values(operators).reduce(
(acc, cur) => { (acc, cur) => {
@@ -205,7 +223,7 @@ export const copyDirectoryData = async ({
) )
).sort((a, b) => Date.parse(b[0].date) - Date.parse(a[0].date)) ).sort((a, b) => Date.parse(b[0].date) - Date.parse(a[0].date))
await Promise.all( await Promise.all(
config.directory.error.files.map(async (key) => { config.app.directory.error.files.map(async (key) => {
await generateAssetsJson(key.key, extractedFolder, targetFolder, { await generateAssetsJson(key.key, extractedFolder, targetFolder, {
useSymLink: false, useSymLink: false,
}) })
@@ -214,17 +232,20 @@ export const copyDirectoryData = async ({
const directoryConfig = { const directoryConfig = {
insight_id: config.insight.id, insight_id: config.insight.id,
app_voice_url: config.directory.voice, app_voice_url: config.app.directory.voice,
voice_folders: config.dir_name.voice, voice_folders: config.dir_name.voice,
directory_folder: config.directory.assets_dir, directory_folder: config.app.directory.assets,
default_background: config.module.background.operator_bg_png, default_background: config.module.background.operator_bg_png,
background_files: backgroundFiles, background_files: backgroundFiles,
background_folder: config.module.assets.background, background_folder: config.module.assets.background,
available_operators: Object.keys(operators), available_operators: Object.keys(operators),
error_files: config.directory.error, error_files: config.app.directory.error,
music_folder: config.module.assets.music, music_folder: config.module.assets.music,
music_mapping: musicMapping.musicFileMapping, music_mapping: musicMapping.musicFileMapping,
operators: operatorConfig, operators: operatorConfig,
default_assets_dir: `${config.app.showcase.assets}/`,
logo_dir: `${config.module.operator.logos}/`,
portraits: `${config.app.directory.portraits}/`,
} }
file.writeSync( file.writeSync(
JSON.stringify(directoryConfig), JSON.stringify(directoryConfig),
@@ -235,7 +256,7 @@ export const copyDirectoryData = async ({
env.generate([ env.generate([
{ {
key: 'app_title', key: 'app_title',
value: config.directory.title, value: config.app.directory.title,
}, },
{ {
key: 'insight_url', key: 'insight_url',
@@ -245,23 +266,51 @@ export const copyDirectoryData = async ({
path.join(dataDir, '.env') path.join(dataDir, '.env')
) )
filesToCopy.map((key) => { const filesToCopy = [
{
src: path.join(
extractedFolder,
config.app.directory.error.voice.file
),
dest: path.join(
targetFolder,
config.app.directory.error.voice.target
),
},
{
src: path.resolve(ASSETS_DIST_DIR, config.module.assets.background),
dest: path.resolve(targetFolder, config.module.assets.background),
},
{
src: path.resolve(ASSETS_DIST_DIR, config.module.assets.music),
dest: path.resolve(targetFolder, config.module.assets.music),
},
{
src: path.resolve(ASSETS_DIST_DIR, config.module.operator.logos),
dest: path.resolve(targetFolder, config.module.operator.logos),
},
]
operatorFilesToCopy.map((key) => {
const portraitName = `${operators[key].fallback_name}_portrait.png` const portraitName = `${operators[key].fallback_name}_portrait.png`
file.cpSync( filesToCopy.push({
path.join( src: path.join(
sourceFolder, sourceFolder,
config.module.operator.operator, config.module.operator.operator,
key, key,
portraitName portraitName
), ),
path.join(targetFolder, portraitName) dest: path.join(
) targetFolder,
config.app.directory.portraits,
portraitName
),
})
}) })
file.cpSync( filesToCopy.forEach((item) => {
path.join(extractedFolder, config.directory.error.voice.file), file.symlink(item.src, item.dest)
path.join(targetFolder, config.directory.error.voice.target) })
)
return directoryConfig return directoryConfig
} }

View File

@@ -1,16 +1,44 @@
{ {
"$schema": "https://turbo.build/schema.json", "$schema": "https://turbo.build/schema.json",
"tasks": { "tasks": {
"@aklive2d/directory#build": { "@aklive2d/directory#dev:directory": {
"inputs": [
"$TURBO_DEFAULT$",
"../../release/**",
"../../packages/assets/dist/**",
"src/**"
],
"dependsOn": ["@aklive2d/showcase#build:directory"],
"persistent": true
},
"@aklive2d/directory#build:directory": {
"inputs": [
"$TURBO_DEFAULT$",
"../../release/**",
"../../packages/assets/dist/**",
"src/**"
],
"outputs": ["../../dist/index.html", "../../dist/_assets/**"],
"dependsOn": ["@aklive2d/showcase#build:directory"]
},
"@aklive2d/showcase#build:directory": {
"env": ["name"], "env": ["name"],
"inputs": ["$TURBO_DEFAULT$", "../../packages/assets/dist/**", "src/**"], "inputs": [
"outputs": ["../../dist/index.html", "../../dist/_assets/**", "../../dist/_directory/**"], "$TURBO_DEFAULT$",
"dependsOn": ["^@aklive2d/showcase#build"] "../../packages/assets/dist/**",
"src/**"
],
"outputs": ["../../release/**"],
"dependsOn": ["@aklive2d/assets#build"]
}, },
"@aklive2d/showcase#build": { "@aklive2d/showcase#build": {
"env": ["name"], "env": ["name"],
"inputs": ["$TURBO_DEFAULT$", "../../packages/assets/dist/**", "src/**"], "inputs": [
"outputs": ["../../dist/**"], "$TURBO_DEFAULT$",
"../../packages/assets/dist/**",
"src/**"
],
"outputs": ["../../release/**"],
"dependsOn": ["@aklive2d/assets#build"] "dependsOn": ["@aklive2d/assets#build"]
}, },
"@aklive2d/background#build": { "@aklive2d/background#build": {
@@ -19,29 +47,49 @@
}, },
"@aklive2d/charword-table#build": { "@aklive2d/charword-table#build": {
"env": ["name"], "env": ["name"],
"inputs": ["../official-info/auto_update/official_info.json", "../operator/operators.yaml"], "inputs": [
"../official-info/auto_update/official_info.json",
"../operator/operators.yaml"
],
"outputs": ["dist/**/charword_table.json"] "outputs": ["dist/**/charword_table.json"]
}, },
"@aklive2d/operator#build": { "@aklive2d/operator#build": {
"env": ["name"], "env": ["name"],
"dependsOn": ["@aklive2d/charword-table#build"], "dependsOn": ["@aklive2d/charword-table#build"],
"inputs": ["../official-info/auto_update/official_info.json", "operators.yaml"], "inputs": [
"../official-info/auto_update/official_info.json",
"operators.yaml"
],
"outputs": ["dist/**"] "outputs": ["dist/**"]
}, },
"@aklive2d/project-json#build": { "@aklive2d/project-json#build": {
"env": ["name"], "env": ["name"],
"dependsOn": ["@aklive2d/background#build", "@aklive2d/charword-table#build", "@aklive2d/music#build"], "dependsOn": [
"@aklive2d/background#build",
"@aklive2d/charword-table#build",
"@aklive2d/music#build"
],
"inputs": ["../operator/operators.yaml"], "inputs": ["../operator/operators.yaml"],
"outputs": ["dist/**"] "outputs": ["dist/**"]
}, },
"@aklive2d/assets#build": { "@aklive2d/assets#build": {
"dependsOn": ["@aklive2d/background#build", "@aklive2d/charword-table#build", "@aklive2d/operator#build", "@aklive2d/project-json#build"], "dependsOn": [
"@aklive2d/background#build",
"@aklive2d/charword-table#build",
"@aklive2d/operator#build",
"@aklive2d/project-json#build"
],
"outputs": ["dist/**"] "outputs": ["dist/**"]
}, },
"build": { "build": {
"env": ["name"], "env": ["name"],
"dependsOn": ["^build"], "dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$"], "inputs": ["$TURBO_DEFAULT$"],
"outputs": ["release/**"]
},
"build:directory": {
"env": ["name"],
"inputs": ["$TURBO_DEFAULT$"],
"outputs": ["dist/**"] "outputs": ["dist/**"]
}, },
"@aklive2d/charword-table#update": { "@aklive2d/charword-table#update": {
@@ -50,7 +98,11 @@
}, },
"@aklive2d/music#update": { "@aklive2d/music#update": {
"cache": false, "cache": false,
"outputs": ["auto_update/audio_data*.json", "auto_update/display_meta_table*.json", "auto_update/music_table.json"] "outputs": [
"auto_update/audio_data*.json",
"auto_update/display_meta_table*.json",
"auto_update/music_table.json"
]
}, },
"@aklive2d/official-info#update": { "@aklive2d/official-info#update": {
"cache": false, "cache": false,
@@ -85,8 +137,6 @@
"persistent": true "persistent": true
}, },
"dev:showcase": { "dev:showcase": {
"env": ["name"],
"dependsOn": ["^@aklive2d/assets#build"],
"cache": false, "cache": false,
"persistent": true "persistent": true
}, },