feat: migrate to turbo (#22)
* feat: migrate top turbo * ci: ci test * fix: fix codeql issues * feat: ci test * chore: lint * chore: misc changes * feat: rename vite helpers * feat: use fetch to handle assets * feat: update directory * feat: fetch charword table * feat: migrate download game data and detect missing voice files * feat: symlink relative path * feat: finish wrangler upload * feat: migrate wrangler download * feat: finish * chore: auto update * ci: update ci * ci: update ci --------- Co-authored-by: Halyul <Halyul@users.noreply.github.com>
This commit is contained in:
1
packages/operator/.gitignore
vendored
Normal file
1
packages/operator/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
data
|
||||
3
packages/operator/.prettierignore
Normal file
3
packages/operator/.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
dist
|
||||
data
|
||||
auto_update
|
||||
60
packages/operator/config.yaml
Normal file
60
packages/operator/config.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
chen: !include config/chen.yaml
|
||||
dusk: !include config/dusk.yaml
|
||||
dusk_everything_is_a_miracle: !include config/dusk_everything_is_a_miracle.yaml
|
||||
ling: !include config/ling.yaml
|
||||
nearl: !include config/nearl.yaml
|
||||
nian: !include config/nian.yaml
|
||||
nian_unfettered_freedom: !include config/nian_unfettered_freedom.yaml
|
||||
phatom_focus: !include config/phatom_focus.yaml
|
||||
rosmontis: !include config/rosmontis.yaml
|
||||
skadi: !include config/skadi.yaml
|
||||
skadi_sublimation: !include config/skadi_sublimation.yaml
|
||||
w: !include config/w.yaml
|
||||
w_wonder: !include config/w_wonder.yaml
|
||||
specter: !include config/specter.yaml
|
||||
gavial: !include config/gavial.yaml
|
||||
surtr_colorful_wonderland: !include config/surtr_colorful_wonderland.yaml
|
||||
lee_trust_your_eyes: !include config/lee_trust_your_eyes.yaml
|
||||
texas_the_omertosa: !include config/texas_the_omertosa.yaml
|
||||
nearl_relight: !include config/nearl_relight.yaml
|
||||
rosmontis_become_anew: !include config/rosmontis_become_anew.yaml
|
||||
passager_dream_in_a_moment: !include config/passager_dream_in_a_moment.yaml
|
||||
mizuki_summer_feast: !include config/mizuki_summer_feast.yaml
|
||||
chongyue: !include config/chongyue.yaml
|
||||
ling_it_does_wash_the_strings: !include config/ling_it_does_wash_the_strings.yaml
|
||||
pozemka_snowy_plains_in_words: !include config/pozemka_snowy_plains_in_words.yaml
|
||||
chen_ten_thousand_mountains: !include config/chen_ten_thousand_mountains.yaml
|
||||
specter_born_as_one: !include config/specter_born_as_one.yaml
|
||||
muelsyse: !include config/muelsyse.yaml
|
||||
kaltsit_remnant: !include config/kaltsit_remnant.yaml
|
||||
eyjafjalla_the_hvit_aska: !include config/eyjafjalla_the_hvit_aska.yaml
|
||||
goldenglow_summer_flowers_fa394: !include config/goldenglow_summer_flowers_fa394.yaml
|
||||
gavial_the_invincible_holiday_hd26: !include config/gavial_the_invincible_holiday_hd26.yaml
|
||||
ling_towering_is_cliff_of_nostalgia: !include config/ling_towering_is_cliff_of_nostalgia.yaml
|
||||
virtuosa: !include config/virtuosa.yaml
|
||||
texas_the_omertosa_wingbreaker: !include config/texas_the_omertosa_wingbreaker.yaml
|
||||
mwynar_w_dali: !include config/mwynar_w_dali.yaml
|
||||
reed_the_frame_shadow_curator: !include config/reed_the_frame_shadow_curator.yaml
|
||||
shu: !include config/shu.yaml
|
||||
lin_heavenly_mirage: !include config/lin_heavenly_mirage.yaml
|
||||
chongyue_alighting: !include config/chongyue_alighting.yaml
|
||||
wisadel: !include config/wisadel.yaml
|
||||
muelsyse_young_branch: !include config/muelsyse_young_branch.yaml
|
||||
skadi_the_corrupting_heart_red_countess: !include config/skadi_the_corrupting_heart_red_countess.yaml
|
||||
ines_under_the_flaming_dome: !include config/ines_under_the_flaming_dome.yaml
|
||||
silverash_never_melting_ice: !include config/silverash_never_melting_ice.yaml
|
||||
reed_the_frame_shadow_summer_flower: !include config/reed_the_frame_shadow_summer_flower.yaml
|
||||
eyjafjalla_the_hvit_aska_a_picnic_before_a_long_trip: !include config/eyjafjalla_the_hvit_aska_a_picnic_before_a_long_trip.yaml
|
||||
pepe: !include config/pepe.yaml
|
||||
nightingale_iakhu_of_flows: !include config/nightingale_iakhu_of_flows.yaml
|
||||
degenbrecher_the_shadow_of_dark_moon: !include config/degenbrecher_the_shadow_of_dark_moon.yaml
|
||||
lappland_the_decadenza: !include config/lappland_the_decadenza.yaml
|
||||
texas_the_omertosa_il_se_de_no: !include config/texas_the_omertosa_il_se_de_no.yaml
|
||||
executor_the_ex_foedere_allmind_as_one: !include config/executor_the_ex_foedere_allmind_as_one.yaml
|
||||
virtuosa_diversity_oneness: !include config/virtuosa_diversity_oneness.yaml
|
||||
chongyue_allround_actor: !include config/chongyue_allround_actor.yaml
|
||||
nian_thunderbolt_director: !include config/nian_thunderbolt_director.yaml
|
||||
amiya_solo_around_the_world: !include config/amiya_solo_around_the_world.yaml
|
||||
zuole_youthful_journey: !include config/zuole_youthful_journey.yaml
|
||||
shu_spring_feast: !include config/shu_spring_feast.yaml
|
||||
yu: !include config/yu.yaml
|
||||
12
packages/operator/config/_template.yaml
Normal file
12
packages/operator/config/_template.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
filename: dyn_illust_char_1013_chen2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1013_chen2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 假日威龙陈
|
||||
en-US: Ch'en/Chen the Holungday
|
||||
use_json: false
|
||||
13
packages/operator/config/amiya_solo_around_the_world.yaml
Normal file
13
packages/operator/config/amiya_solo_around_the_world.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1037_amiya3_sale#13
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1037_amiya3_sale#13
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 寰宇独奏 · 阿米娅
|
||||
en-US: Solo Around The World / Amiya
|
||||
use_json: false
|
||||
official_id: '202412473'
|
||||
13
packages/operator/config/chen.yaml
Normal file
13
packages/operator/config/chen.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1013_chen2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1013_chen2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: 1
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 假日威龙陈
|
||||
en-US: Ch'en/Chen the Holungday
|
||||
use_json: false
|
||||
official_id: '20220345'
|
||||
13
packages/operator/config/chen_ten_thousand_mountains.yaml
Normal file
13
packages/operator/config/chen_ten_thousand_mountains.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1013_chen2_boc#6
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1013_chen2_boc#6
|
||||
viewport_left: -1
|
||||
viewport_right: 1
|
||||
viewport_top: 2
|
||||
viewport_bottom: -1
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 万重山 · 假日威龙陈
|
||||
en-US: Ten Thousand Mountains / Ch'en/Chen the Holungday
|
||||
use_json: false
|
||||
official_id: '202304659'
|
||||
13
packages/operator/config/chongyue.yaml
Normal file
13
packages/operator/config/chongyue.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2024_chyue
|
||||
logo: logo_sui
|
||||
fallback_name: char_2024_chyue_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 重岳
|
||||
en-US: Chongyue
|
||||
use_json: false
|
||||
official_id: '202301606'
|
||||
13
packages/operator/config/chongyue_alighting.yaml
Normal file
13
packages/operator/config/chongyue_alighting.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2024_chyue_nian#10
|
||||
logo: logo_sui
|
||||
fallback_name: char_2024_chyue_nian#10
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 何处栖 · 重岳
|
||||
en-US: Alighting / Chongyue
|
||||
use_json: false
|
||||
official_id: '202401812'
|
||||
13
packages/operator/config/chongyue_allround_actor.yaml
Normal file
13
packages/operator/config/chongyue_allround_actor.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2024_chyue_cfa#1
|
||||
logo: logo_sui
|
||||
fallback_name: char_2024_chyue_cfa#1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 全能演员 · 重岳
|
||||
en-US: All-Round Actor / Chongyue
|
||||
use_json: false
|
||||
official_id: '202412452'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4116_blkkgt_witch#5
|
||||
logo: logo_kjerag
|
||||
fallback_name: char_4116_blkkgt_witch#5
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 暗月的影子 · 锏
|
||||
en-US: The Shadow Of The Dark Moon / Degenbrecher
|
||||
use_json: false
|
||||
official_id: '202410426'
|
||||
13
packages/operator/config/dusk.yaml
Normal file
13
packages/operator/config/dusk.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2015_dusk
|
||||
logo: logo_sui
|
||||
fallback_name: char_2015_dusk_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 夕
|
||||
en-US: Dusk
|
||||
use_json: false
|
||||
official_id: '202203263'
|
||||
13
packages/operator/config/dusk_everything_is_a_miracle.yaml
Normal file
13
packages/operator/config/dusk_everything_is_a_miracle.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2015_dusk_nian#7
|
||||
logo: logo_sui
|
||||
fallback_name: char_2015_dusk_nian#7
|
||||
viewport_left: 10
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 染尘烟 · 夕
|
||||
en-US: Everything is a Miracle / Dusk
|
||||
use_json: false
|
||||
official_id: '20220321'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1032_excu2_sale#12
|
||||
logo: logo_Laterano
|
||||
fallback_name: char_1032_excu2_sale#12
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 众志归一 · 圣约送葬人
|
||||
en-US: Allmind as one / Executor the Ex Foedere
|
||||
use_json: false
|
||||
official_id: '202410488'
|
||||
13
packages/operator/config/eyjafjalla_the_hvit_aska.yaml
Normal file
13
packages/operator/config/eyjafjalla_the_hvit_aska.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1016_agoat2
|
||||
logo: logo_Leithanien
|
||||
fallback_name: char_1016_agoat2_2
|
||||
viewport_left: 1
|
||||
viewport_right: 0
|
||||
viewport_top: 5
|
||||
viewport_bottom: 5
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 纯烬艾雅法拉
|
||||
en-US: Eyjafjalla the Hvít Aska
|
||||
use_json: false
|
||||
official_id: '202307865'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1016_agoat2_epoque#34
|
||||
logo: logo_Leithanien
|
||||
fallback_name: char_1016_agoat2_epoque#34
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 远行前的野餐 · 纯烬艾雅法拉
|
||||
en-US: A Picnic Before A Long Trip / Eyjafjalla the Hvít Aska
|
||||
use_json: true
|
||||
official_id: '202407072'
|
||||
13
packages/operator/config/gavial.yaml
Normal file
13
packages/operator/config/gavial.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1026_gvial2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1026_gvial2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 百练嘉维尔
|
||||
en-US: Gavial the Invincible
|
||||
use_json: false
|
||||
official_id: '202208258'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1026_gvial2_summer#12
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1026_gvial2_summer#12
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 悠然假日 HD26 · 百炼嘉维尔
|
||||
en-US: Holiday HD26 / Gavial the Invincible
|
||||
use_json: false
|
||||
official_id: '202307886'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_377_gdglow_summer#12
|
||||
logo: logo_victoria
|
||||
fallback_name: char_377_gdglow_summer#12
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 夏卉 FA394 · 澄闪
|
||||
en-US: Summer Flowers FA394 / Goldenglow
|
||||
use_json: false
|
||||
official_id: '202307824'
|
||||
13
packages/operator/config/ines_under_the_flaming_dome.yaml
Normal file
13
packages/operator/config/ines_under_the_flaming_dome.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4087_ines_boc#8
|
||||
logo: logo_babel
|
||||
fallback_name: char_4087_ines_boc#8
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 燃烧天穹下 · 伊内丝
|
||||
en-US: Under the Flaming Dome / Ines
|
||||
use_json: false
|
||||
official_id: '202404087'
|
||||
13
packages/operator/config/kaltsit_remnant.yaml
Normal file
13
packages/operator/config/kaltsit_remnant.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_003_kalts_boc#6
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_003_kalts_boc#6
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 残余 · 凯尔希
|
||||
en-US: Remnant / Kal'tsit
|
||||
use_json: false
|
||||
official_id: '202304833'
|
||||
13
packages/operator/config/lappland_the_decadenza.yaml
Normal file
13
packages/operator/config/lappland_the_decadenza.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1038_whitw2
|
||||
logo: logo_chiave
|
||||
fallback_name: char_1038_whitw2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 荒芜拉普兰德
|
||||
en-US: Lappland the Decadenza
|
||||
use_json: false
|
||||
official_id: '202410440'
|
||||
13
packages/operator/config/lee_trust_your_eyes.yaml
Normal file
13
packages/operator/config/lee_trust_your_eyes.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_322_lmlee_witch#3
|
||||
logo: logo_lee
|
||||
fallback_name: char_322_lmlee_witch#3
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 手到牌来 · 老鲤
|
||||
en-US: Trust Your Eyes / Lee
|
||||
use_json: false
|
||||
official_id: '202210279'
|
||||
13
packages/operator/config/lin_heavenly_mirage.yaml
Normal file
13
packages/operator/config/lin_heavenly_mirage.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4080_lin_nian#10
|
||||
logo: logo_lungmen
|
||||
fallback_name: char_4080_lin_nian#10
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 列瑶台 · 林
|
||||
en-US: Heavenly Mirage / Lin
|
||||
use_json: false
|
||||
official_id: '202401034'
|
||||
13
packages/operator/config/ling.yaml
Normal file
13
packages/operator/config/ling.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2023_ling
|
||||
logo: logo_sui
|
||||
fallback_name: char_2023_ling_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 令
|
||||
en-US: Ling
|
||||
use_json: false
|
||||
official_id: '20220383'
|
||||
13
packages/operator/config/ling_it_does_wash_the_strings.yaml
Normal file
13
packages/operator/config/ling_it_does_wash_the_strings.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2023_ling_nian#9
|
||||
logo: logo_sui
|
||||
fallback_name: char_2023_ling_nian#9
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 濯缨 · 令
|
||||
en-US: It Does Wash the Strings / Ling
|
||||
use_json: false
|
||||
official_id: '202301647'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2023_ling_ncg#1
|
||||
logo: logo_sui
|
||||
fallback_name: char_2023_ling_ncg#1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 崖高梦远 · 令
|
||||
en-US: Towering is Cliff of Nostalgia
|
||||
use_json: false
|
||||
official_id: '202308807'
|
||||
13
packages/operator/config/mizuki_summer_feast.yaml
Normal file
13
packages/operator/config/mizuki_summer_feast.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_437_mizuki_sale#7
|
||||
logo: logo_higashi
|
||||
fallback_name: char_437_mizuki_sale#7
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 夏日餮宴 · 水月
|
||||
en-US: Summer Feast / Mizuki
|
||||
use_json: false
|
||||
official_id: '202211685'
|
||||
13
packages/operator/config/muelsyse.yaml
Normal file
13
packages/operator/config/muelsyse.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_249_mlyss
|
||||
logo: logo_rhine
|
||||
fallback_name: char_249_mlyss_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 3
|
||||
viewport_bottom: 2
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 缪尔赛思
|
||||
en-US: Muelsyse
|
||||
use_json: false
|
||||
official_id: '202304611'
|
||||
13
packages/operator/config/muelsyse_young_branch.yaml
Normal file
13
packages/operator/config/muelsyse_young_branch.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_249_mlyss_boc#8
|
||||
logo: logo_rhine
|
||||
fallback_name: char_249_mlyss_boc#8
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 新枝 · 缪尔赛思
|
||||
en-US: Young Branch / Muelsyse
|
||||
use_json: false
|
||||
official_id: '202404090'
|
||||
13
packages/operator/config/mwynar_w_dali.yaml
Normal file
13
packages/operator/config/mwynar_w_dali.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4064_mlynar_epoque#28
|
||||
logo: logo_kazimierz
|
||||
fallback_name: char_4064_mlynar_epoque#28
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 远路 · 玛恩纳
|
||||
en-US: W Dali / Młynar
|
||||
use_json: false
|
||||
official_id: '202310850'
|
||||
13
packages/operator/config/nearl.yaml
Normal file
13
packages/operator/config/nearl.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1014_nearl2
|
||||
logo: logo_kazimierz
|
||||
fallback_name: char_1014_nearl2_2
|
||||
viewport_left: 2
|
||||
viewport_right: 3
|
||||
viewport_top: 10
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 耀骑士临光
|
||||
en-US: Nearl the Radiant Knight
|
||||
use_json: false
|
||||
official_id: '20220304'
|
||||
13
packages/operator/config/nearl_relight.yaml
Normal file
13
packages/operator/config/nearl_relight.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1014_nearl2_epoque#17
|
||||
logo: logo_kazimierz
|
||||
fallback_name: char_1014_nearl2_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 复现荣光 · 耀骑士临光
|
||||
en-US: Relight / Nearl
|
||||
use_json: false
|
||||
official_id: '202210623'
|
||||
13
packages/operator/config/nian.yaml
Normal file
13
packages/operator/config/nian.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2014_nian
|
||||
logo: logo_sui
|
||||
fallback_name: char_2014_nian_2
|
||||
viewport_left: 2
|
||||
viewport_right: 2
|
||||
viewport_top: 3
|
||||
viewport_bottom: 5
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 年
|
||||
en-US: Nian
|
||||
use_json: false
|
||||
official_id: '202203231'
|
||||
13
packages/operator/config/nian_thunderbolt_director.yaml
Normal file
13
packages/operator/config/nian_thunderbolt_director.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2014_nian_cfa#1
|
||||
logo: logo_sui
|
||||
fallback_name: char_2014_nian_cfa#1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 霹雳导演 · 年
|
||||
en-US: Thunderbolt Director / Nian
|
||||
use_json: false
|
||||
official_id: '202412491'
|
||||
13
packages/operator/config/nian_unfettered_freedom.yaml
Normal file
13
packages/operator/config/nian_unfettered_freedom.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2014_nian_nian#4
|
||||
logo: logo_sui
|
||||
fallback_name: char_2014_nian_nian#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 乐逍遥 · 年
|
||||
en-US: Unfettered Freedom / Nian
|
||||
use_json: false
|
||||
official_id: '20220362'
|
||||
13
packages/operator/config/nightingale_iakhu_of_flows.yaml
Normal file
13
packages/operator/config/nightingale_iakhu_of_flows.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_179_cgbird_sightseer#1
|
||||
logo: logo_followers
|
||||
fallback_name: char_179_cgbird_sightseer#1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 流辉 · 夜莺
|
||||
en-US: Iakhu of Flows / Nightingale
|
||||
use_json: false
|
||||
official_id: '202407435'
|
||||
13
packages/operator/config/passager_dream_in_a_moment.yaml
Normal file
13
packages/operator/config/passager_dream_in_a_moment.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_472_pasngr_epoque#17
|
||||
logo: logo_sargon
|
||||
fallback_name: char_472_pasngr_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 今昔须臾之梦 · 异客
|
||||
en-US: Dream in a Moment / Passager
|
||||
use_json: false
|
||||
official_id: '202210664'
|
||||
13
packages/operator/config/pepe.yaml
Normal file
13
packages/operator/config/pepe.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4058_pepe
|
||||
logo: logo_sargon
|
||||
fallback_name: char_4058_pepe_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 佩佩
|
||||
en-US: Pepe
|
||||
use_json: true
|
||||
official_id: '202407013'
|
||||
13
packages/operator/config/phatom_focus.yaml
Normal file
13
packages/operator/config/phatom_focus.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_250_phatom_sale#4
|
||||
logo: logo_victoria
|
||||
fallback_name: char_250_phatom_sale#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 5
|
||||
viewport_bottom: 1
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 焦点 · 傀影
|
||||
en-US: Focus / Phatom
|
||||
use_json: false
|
||||
official_id: '202203222'
|
||||
13
packages/operator/config/pozemka_snowy_plains_in_words.yaml
Normal file
13
packages/operator/config/pozemka_snowy_plains_in_words.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4055_bgsnow_wild#7
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_4055_bgsnow_wild#7
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 字句中的雪原 · 鸿雪
|
||||
en-US: Snowy Plains in Words / Позёмка
|
||||
use_json: false
|
||||
official_id: '202302698'
|
||||
13
packages/operator/config/reed_the_frame_shadow_curator.yaml
Normal file
13
packages/operator/config/reed_the_frame_shadow_curator.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1020_reed2_epoque#30
|
||||
logo: logo_dublinn
|
||||
fallback_name: char_1020_reed2_epoque#30
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 博物 · 焰影苇草
|
||||
en-US: Curator / Reed The Flame Shadow
|
||||
use_json: false
|
||||
official_id: '202401871'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1020_reed2_summer#17
|
||||
logo: logo_dublinn
|
||||
fallback_name: char_1020_reed2_summer#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 夏卉 FA075 · 焰影苇草
|
||||
en-US: Summer Flowers FA075 / Reed The Flame Shadow
|
||||
use_json: true
|
||||
official_id: '202407051'
|
||||
13
packages/operator/config/rosmontis.yaml
Normal file
13
packages/operator/config/rosmontis.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_391_rosmon
|
||||
logo: logo_elite
|
||||
fallback_name: char_391_rosmon_2
|
||||
viewport_left: 0
|
||||
viewport_right: -14
|
||||
viewport_top: -38
|
||||
viewport_bottom: -1
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 迷迭香
|
||||
en-US: Rosmontis
|
||||
use_json: false
|
||||
official_id: '20220378'
|
||||
13
packages/operator/config/rosmontis_become_anew.yaml
Normal file
13
packages/operator/config/rosmontis_become_anew.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_391_rosmon_epoque#17
|
||||
logo: logo_elite
|
||||
fallback_name: char_391_rosmon_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 拥抱新生 · 迷迭香
|
||||
en-US: Become Anew / Rosmontis
|
||||
use_json: false
|
||||
official_id: '202210632'
|
||||
13
packages/operator/config/shu.yaml
Normal file
13
packages/operator/config/shu.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2025_shu
|
||||
logo: logo_sui
|
||||
fallback_name: char_2025_shu_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 黍
|
||||
en-US: Shu
|
||||
use_json: false
|
||||
official_id: '202401025'
|
||||
13
packages/operator/config/shu_spring_feast.yaml
Normal file
13
packages/operator/config/shu_spring_feast.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2025_shu_nian#11
|
||||
logo: logo_sui
|
||||
fallback_name: char_2025_shu_nian#11
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 春日宴 · 黍
|
||||
en-US: Spring Feast / Shu
|
||||
use_json: false
|
||||
official_id: '202501936'
|
||||
13
packages/operator/config/silverash_never_melting_ice.yaml
Normal file
13
packages/operator/config/silverash_never_melting_ice.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_172_svrash_ambienceSynesthesia#4
|
||||
logo: logo_kjerag
|
||||
fallback_name: char_172_svrash_ambienceSynesthesia#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 不融冰 · 银灰
|
||||
en-US: Never-Melting Ice / SilverAsh
|
||||
use_json: false
|
||||
official_id: '202404066'
|
||||
13
packages/operator/config/skadi.yaml
Normal file
13
packages/operator/config/skadi.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1012_skadi2
|
||||
logo: logo_egir
|
||||
fallback_name: char_1012_skadi2_2
|
||||
viewport_left: -5
|
||||
viewport_right: -10
|
||||
viewport_top: 0
|
||||
viewport_bottom: -12
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 浊心斯卡蒂
|
||||
en-US: Skadi the Corrupting Heart
|
||||
use_json: false
|
||||
official_id: '20220396'
|
||||
13
packages/operator/config/skadi_sublimation.yaml
Normal file
13
packages/operator/config/skadi_sublimation.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1012_skadi2_boc#4
|
||||
logo: logo_egir
|
||||
fallback_name: char_1012_skadi2_boc#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 升华 · 浊心斯卡蒂
|
||||
en-US: Sublimation / Skadi the Corrupting Heart
|
||||
use_json: false
|
||||
official_id: '202204205'
|
||||
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1012_skadi2_iteration#2
|
||||
logo: logo_egir
|
||||
fallback_name: char_1012_skadi2_iteration#2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 红女爵 · 浊心斯卡蒂
|
||||
en-US: Red Countess / Skadi the Corrupting Heart
|
||||
use_json: false
|
||||
official_id: '202404008'
|
||||
13
packages/operator/config/specter.yaml
Normal file
13
packages/operator/config/specter.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1023_ghost2
|
||||
logo: logo_abyssal
|
||||
fallback_name: char_1023_ghost2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 归溟幽灵鲨
|
||||
en-US: Specter the Unchained
|
||||
use_json: false
|
||||
official_id: '202204284'
|
||||
13
packages/operator/config/specter_born_as_one.yaml
Normal file
13
packages/operator/config/specter_born_as_one.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1023_ghost2_boc#6
|
||||
logo: logo_abyssal
|
||||
fallback_name: char_1023_ghost2_boc#6
|
||||
viewport_left: -1
|
||||
viewport_right: 1
|
||||
viewport_top: 0
|
||||
viewport_bottom: 1
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 生而为一 · 归溟幽灵鲨
|
||||
en-US: Born as One / Specter the Unchained
|
||||
use_json: false
|
||||
official_id: '202304670'
|
||||
13
packages/operator/config/surtr_colorful_wonderland.yaml
Normal file
13
packages/operator/config/surtr_colorful_wonderland.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_350_surtr_summer#9
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_350_surtr_summer#9
|
||||
viewport_left: 0
|
||||
viewport_right: 6
|
||||
viewport_top: 1
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
codename:
|
||||
zh-CN: 缤纷奇境 CW03 · 史尔特尔
|
||||
en-US: Colorful Wonderland CW03 / Surtr
|
||||
use_json: false
|
||||
official_id: '202208297'
|
||||
13
packages/operator/config/texas_the_omertosa.yaml
Normal file
13
packages/operator/config/texas_the_omertosa.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1028_texas2
|
||||
logo: logo_penguin
|
||||
fallback_name: char_1028_texas2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 缄默德克萨斯
|
||||
en-US: Texas the Omertosa
|
||||
use_json: false
|
||||
official_id: '202210210'
|
||||
13
packages/operator/config/texas_the_omertosa_il_se_de_no.yaml
Normal file
13
packages/operator/config/texas_the_omertosa_il_se_de_no.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1028_texas2_epoque#36
|
||||
logo: logo_penguin
|
||||
fallback_name: char_1028_texas2_epoque#36
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 幽兰秘辛 · 缄默德克萨斯
|
||||
en-US: Il Segreto Della Notte / Texas the Omertosa
|
||||
use_json: false
|
||||
official_id: '202410409'
|
||||
13
packages/operator/config/texas_the_omertosa_wingbreaker.yaml
Normal file
13
packages/operator/config/texas_the_omertosa_wingbreaker.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1028_texas2_iteration#1
|
||||
logo: logo_penguin
|
||||
fallback_name: char_1028_texas2_iteration#1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 破翼者 · 缄默德克萨斯
|
||||
en-US: Wingbreaker / Texas the Omertosa
|
||||
use_json: false
|
||||
official_id: '202310899'
|
||||
13
packages/operator/config/virtuosa.yaml
Normal file
13
packages/operator/config/virtuosa.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_245_cello
|
||||
logo: logo_Laterano
|
||||
fallback_name: char_245_cello_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 塑心
|
||||
en-US: Virtuosa
|
||||
use_json: false
|
||||
official_id: '202310848'
|
||||
13
packages/operator/config/virtuosa_diversity_oneness.yaml
Normal file
13
packages/operator/config/virtuosa_diversity_oneness.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_245_cello_sale#12
|
||||
logo: logo_Laterano
|
||||
fallback_name: char_245_cello_sale#12
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 无我唯识 · 塑心
|
||||
en-US: Diversity Oneness / Virtuosa
|
||||
use_json: false
|
||||
official_id: '202410467'
|
||||
13
packages/operator/config/w.yaml
Normal file
13
packages/operator/config/w.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_113_cqbw
|
||||
logo: logo_babel
|
||||
fallback_name: char_113_cqbw_2
|
||||
viewport_left: 3
|
||||
viewport_right: -3
|
||||
viewport_top: 0
|
||||
viewport_bottom: 1
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: W
|
||||
en-US: W
|
||||
use_json: false
|
||||
official_id: '20220319'
|
||||
13
packages/operator/config/w_wonder.yaml
Normal file
13
packages/operator/config/w_wonder.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_113_cqbw_epoque#7
|
||||
logo: logo_babel
|
||||
fallback_name: char_113_cqbw_epoque#7
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: -4
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 恍惚 · W
|
||||
en-US: Wonder / W
|
||||
use_json: false
|
||||
official_id: '202206246'
|
||||
13
packages/operator/config/wisadel.yaml
Normal file
13
packages/operator/config/wisadel.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_1035_wisdel
|
||||
logo: logo_babel
|
||||
fallback_name: char_1035_wisdel_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 维什戴尔
|
||||
en-US: Wisadel
|
||||
use_json: false
|
||||
official_id: '202404049'
|
||||
13
packages/operator/config/yu.yaml
Normal file
13
packages/operator/config/yu.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_2026_yu
|
||||
logo: logo_sui
|
||||
fallback_name: char_2026_yu_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 余
|
||||
en-US: Yu
|
||||
use_json: false
|
||||
official_id: '202501414'
|
||||
13
packages/operator/config/zuole_youthful_journey.yaml
Normal file
13
packages/operator/config/zuole_youthful_journey.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
filename: dyn_illust_char_4121_zuole_nian#11
|
||||
logo: logo_yan
|
||||
fallback_name: char_4121_zuole_nian#11
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
codename:
|
||||
zh-CN: 少年游 · 左乐
|
||||
en-US: Youthful Journey / Zuo Le
|
||||
use_json: false
|
||||
official_id: '202501927'
|
||||
3
packages/operator/eslint.config.js
Normal file
3
packages/operator/eslint.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import baseConfig from '@aklive2d/eslint-config'
|
||||
/** @type {import('eslint').Config} */
|
||||
export default [...baseConfig]
|
||||
276
packages/operator/index.js
Normal file
276
packages/operator/index.js
Normal file
@@ -0,0 +1,276 @@
|
||||
import path from 'node:path'
|
||||
import { stringify } from 'yaml'
|
||||
import { yaml, file, alphaComposite } from '@aklive2d/libs'
|
||||
import config from '@aklive2d/config'
|
||||
import { mapping as officialInfoMapping } from '@aklive2d/official-info'
|
||||
|
||||
export const CONFIG_PATH = path.resolve(
|
||||
import.meta.dirname,
|
||||
config.module.operator.config_yaml
|
||||
)
|
||||
const CONFIG = yaml.read(CONFIG_PATH)
|
||||
export const OPERATOR_SOURCE_FOLDER = path.resolve(
|
||||
import.meta.dirname,
|
||||
config.dir_name.data
|
||||
)
|
||||
const DIST_DIR = path.join(import.meta.dirname, config.dir_name.dist)
|
||||
|
||||
const getVoiceFolders = (name) => {
|
||||
return config.dir_name.voice.sub.map((sub) =>
|
||||
path.join(
|
||||
OPERATOR_SOURCE_FOLDER,
|
||||
name,
|
||||
config.dir_name.voice.main,
|
||||
sub.name
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const getExtractedFolder = (name) => {
|
||||
return path.join(OPERATOR_SOURCE_FOLDER, name, config.dir_name.extracted)
|
||||
}
|
||||
|
||||
const getConfigFolder = () => {
|
||||
return path.join(import.meta.dirname, config.module.operator.config)
|
||||
}
|
||||
|
||||
const getDistFolder = (name) => {
|
||||
return path.join(DIST_DIR, config.dir_name.operator, name)
|
||||
}
|
||||
|
||||
export const has = (name) => {
|
||||
return Object.keys(operators).includes(name)
|
||||
}
|
||||
|
||||
const generateMapping = () => {
|
||||
if (officialInfoMapping) {
|
||||
for (const [operatorName, operator] of Object.entries(CONFIG)) {
|
||||
const operatorInfo = officialInfoMapping[operator.official_id]
|
||||
// add title
|
||||
operator.title = `${config.module.operator.title['en-US']}${operator.codename['en-US']} - ${config.module.operator.title['zh-CN']}${operator.codename['zh-CN']}`
|
||||
// add type
|
||||
operator.type = operatorInfo.type
|
||||
|
||||
// add link
|
||||
operator.link = operatorName
|
||||
|
||||
// id
|
||||
operator.id = getOperatorId(operator.filename).replace(
|
||||
/^(char_)(\d+)(_.+)$/g,
|
||||
'$2'
|
||||
)
|
||||
|
||||
operator.date = operatorInfo.date
|
||||
}
|
||||
}
|
||||
|
||||
return CONFIG
|
||||
}
|
||||
|
||||
const copyVoices = (name) => {
|
||||
file.symlinkAll(
|
||||
path.join(OPERATOR_SOURCE_FOLDER, name, config.dir_name.voice.main),
|
||||
path.join(DIST_DIR, config.dir_name.voice.main, name)
|
||||
)
|
||||
}
|
||||
|
||||
const copyLogos = () => {
|
||||
file.symlink(
|
||||
path.join(OPERATOR_SOURCE_FOLDER, config.module.operator.logos_assets),
|
||||
path.join(DIST_DIR, config.dir_name.logos)
|
||||
)
|
||||
}
|
||||
|
||||
const operators = generateMapping()
|
||||
|
||||
export default operators
|
||||
|
||||
export function getOperatorId(name, matcher = '$2$3$4') {
|
||||
return name.replace(/^(.*)(char_[\d]+)(_[A-Za-z0-9]+)(|_.*)$/g, matcher)
|
||||
}
|
||||
|
||||
export const getOperatorAlternativeId = (id) => {
|
||||
return getOperatorId(id, '$2$3')
|
||||
}
|
||||
|
||||
export const build = async (namesToBuild) => {
|
||||
const names = !namesToBuild.length ? Object.keys(operators) : namesToBuild
|
||||
console.log('Generating assets for', names.length, 'operators')
|
||||
for (const name of names) {
|
||||
await generateAssets(name)
|
||||
copyVoices(name)
|
||||
}
|
||||
copyLogos()
|
||||
}
|
||||
|
||||
const generateAssets = async (name) => {
|
||||
const extractedDir = getExtractedFolder(name)
|
||||
const outDir = getDistFolder(name)
|
||||
file.rmdir(outDir)
|
||||
file.mkdir(outDir)
|
||||
|
||||
const fallback_name = operators[name].fallback_name
|
||||
const fallbackFilename = `${fallback_name}.png`
|
||||
const alphaCompositeFilename = `${path.parse(fallbackFilename).name}[alpha].png`
|
||||
if (file.exists(path.join(extractedDir, alphaCompositeFilename))) {
|
||||
const fallbackBuffer = await alphaComposite.process(
|
||||
fallbackFilename,
|
||||
alphaCompositeFilename,
|
||||
extractedDir
|
||||
)
|
||||
file.writeSync(
|
||||
fallbackBuffer,
|
||||
path.join(getDistFolder(name), fallbackFilename)
|
||||
)
|
||||
} else {
|
||||
await file.copy(
|
||||
path.join(extractedDir, fallbackFilename),
|
||||
path.join(getDistFolder(name), fallbackFilename)
|
||||
)
|
||||
}
|
||||
|
||||
// generate portrait
|
||||
const portraitDir = path.join(
|
||||
OPERATOR_SOURCE_FOLDER,
|
||||
config.module.operator.portraits
|
||||
)
|
||||
const portraitHub = JSON.parse(
|
||||
file.readSync(
|
||||
path.join(
|
||||
portraitDir,
|
||||
config.module.operator.MonoBehaviour,
|
||||
'portrait_hub.json'
|
||||
)
|
||||
)
|
||||
)
|
||||
const fallback_name_lowerCase = fallback_name.toLowerCase()
|
||||
const portraitAtlas = portraitHub._sprites.find(
|
||||
(item) => item.name.toLowerCase() === fallback_name_lowerCase
|
||||
).atlas
|
||||
const portraitJson = JSON.parse(
|
||||
file.readSync(
|
||||
path.join(
|
||||
portraitDir,
|
||||
config.module.operator.MonoBehaviour,
|
||||
`portraits#${portraitAtlas}.json`
|
||||
)
|
||||
)
|
||||
)
|
||||
const item = portraitJson._sprites.find(
|
||||
(item) => item.name.toLowerCase() === fallback_name_lowerCase
|
||||
)
|
||||
const rect = {
|
||||
...item.rect,
|
||||
rotate: item.rotate,
|
||||
}
|
||||
const protraitFilename = `portraits#${portraitAtlas}.png`
|
||||
const portraitBuffer = await alphaComposite.process(
|
||||
protraitFilename,
|
||||
`${path.parse(protraitFilename).name}a.png`,
|
||||
path.join(portraitDir, config.module.operator.Texture2D)
|
||||
)
|
||||
const croppedBuffer = await alphaComposite.crop(portraitBuffer, rect)
|
||||
file.writeSync(
|
||||
croppedBuffer,
|
||||
path.join(getDistFolder(name), `${fallback_name}_portrait.png`)
|
||||
)
|
||||
|
||||
await generateAssetsJson(
|
||||
operators[name].filename,
|
||||
extractedDir,
|
||||
getDistFolder(name),
|
||||
{
|
||||
useJSON: operators[name].use_json,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const generateAssetsJson = async (
|
||||
filename,
|
||||
extractedDir,
|
||||
targetDir,
|
||||
_opts = {
|
||||
useJSON: false,
|
||||
useSymLink: true,
|
||||
}
|
||||
) => {
|
||||
const assetsJson = []
|
||||
|
||||
let skelFilename
|
||||
if (_opts.useJSON) {
|
||||
skelFilename = `${filename}.json`
|
||||
} else {
|
||||
skelFilename = `${filename}.skel`
|
||||
}
|
||||
const atlasFilename = `${filename}.atlas`
|
||||
const atlasPath = path.join(extractedDir, atlasFilename)
|
||||
let atlas = await file.read(atlasPath)
|
||||
const matches = atlas.match(new RegExp(/(.*).png/g))
|
||||
for (const item of matches) {
|
||||
let buffer
|
||||
const alphaCompositeFilename = `${path.parse(item).name}[alpha].png`
|
||||
if (file.exists(path.join(extractedDir, alphaCompositeFilename))) {
|
||||
buffer = await alphaComposite.process(
|
||||
item,
|
||||
alphaCompositeFilename,
|
||||
extractedDir
|
||||
)
|
||||
} else {
|
||||
buffer = await alphaComposite.toBuffer(item, extractedDir)
|
||||
}
|
||||
assetsJson.push({
|
||||
filename: item,
|
||||
content: buffer,
|
||||
})
|
||||
atlas = atlas.replace(item, item.replace(/#/g, '%23'))
|
||||
}
|
||||
assetsJson.push({
|
||||
filename: skelFilename,
|
||||
path: path.join(extractedDir, skelFilename),
|
||||
})
|
||||
assetsJson.push({
|
||||
filename: atlasFilename,
|
||||
content: atlas,
|
||||
})
|
||||
assetsJson.map((item) => {
|
||||
const dir = path.join(targetDir, item.filename)
|
||||
if (item.content) {
|
||||
file.writeSync(item.content, dir)
|
||||
} else {
|
||||
if (_opts.useSymLink) {
|
||||
file.symlink(item.path, dir)
|
||||
} else {
|
||||
file.cpSync(item.path, dir)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const init = (name, id) => {
|
||||
const voiceFolders = getVoiceFolders(name)
|
||||
const extractedFolder = getExtractedFolder(name)
|
||||
const operatorConfigFolder = getConfigFolder()
|
||||
const foldersToCreate = [extractedFolder, ...voiceFolders]
|
||||
|
||||
const template = yaml.read(
|
||||
path.resolve(operatorConfigFolder, config.module.operator.template_yaml)
|
||||
)
|
||||
foldersToCreate.forEach((dir) => {
|
||||
file.mkdir(dir)
|
||||
})
|
||||
const currentOpertor = officialInfoMapping[id]
|
||||
if (currentOpertor === undefined) {
|
||||
throw new Error('Invalid operator id')
|
||||
}
|
||||
template.official_id = currentOpertor.id
|
||||
template.codename = currentOpertor.codename
|
||||
|
||||
file.writeSync(
|
||||
stringify(template),
|
||||
path.resolve(operatorConfigFolder, `${name}.yaml`)
|
||||
)
|
||||
file.appendSync(
|
||||
`\n${name}: !include ${config.module.operator.config}/${name}.yaml`,
|
||||
CONFIG_PATH
|
||||
)
|
||||
}
|
||||
20
packages/operator/package.json
Normal file
20
packages/operator/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@aklive2d/operator",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"yaml": "^2.7.0",
|
||||
"@aklive2d/libs": "workspace:*",
|
||||
"@aklive2d/config": "workspace:*",
|
||||
"@aklive2d/official-info": "workspace:*",
|
||||
"@aklive2d/eslint-config": "workspace:*",
|
||||
"@aklive2d/prettier-config": "workspace:*"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "mode=build node runner.js",
|
||||
"init": "mode=init node runner.js",
|
||||
"lint": "eslint \"*.js\" \"**/*.js\" && prettier --check ."
|
||||
}
|
||||
}
|
||||
11
packages/operator/prettier.config.js
Normal file
11
packages/operator/prettier.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import baseConfig from '@aklive2d/prettier-config'
|
||||
|
||||
/**
|
||||
* @type {import("prettier").Config}
|
||||
*/
|
||||
const config = {
|
||||
...baseConfig,
|
||||
semi: false,
|
||||
}
|
||||
|
||||
export default config
|
||||
38
packages/operator/runner.js
Normal file
38
packages/operator/runner.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { envParser } from '@aklive2d/libs'
|
||||
import { build, init } from './index.js'
|
||||
|
||||
async function main() {
|
||||
const { mode, name, id } = envParser.parse({
|
||||
mode: {
|
||||
type: 'string',
|
||||
short: 'm',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
short: 'n',
|
||||
multiple: true,
|
||||
default: [],
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
})
|
||||
switch (mode) {
|
||||
case 'build':
|
||||
await build(name)
|
||||
break
|
||||
case 'init':
|
||||
if (!name.length) {
|
||||
throw new Error('Please set the operator name.')
|
||||
}
|
||||
if (!id) {
|
||||
throw new Error('Please set the operator id.')
|
||||
}
|
||||
init(name[0], id)
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unknown mode: ${mode}`)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user