skytnt commited on
Commit
c8b8b38
·
1 Parent(s): 7512ef4
Files changed (37) hide show
  1. .gitignore +1 -0
  2. app.py +1 -1
  3. frontend/README.md +2 -0
  4. frontend/babel.config.js +5 -0
  5. frontend/package.json +54 -0
  6. {static → frontend/public}/dict/base.datgz +0 -0
  7. {static → frontend/public}/dict/cc.datgz +0 -0
  8. {static → frontend/public}/dict/check.datgz +0 -0
  9. {static → frontend/public}/dict/tid.datgz +0 -0
  10. {static → frontend/public}/dict/tid_map.datgz +0 -0
  11. {static → frontend/public}/dict/tid_pos.datgz +0 -0
  12. {static → frontend/public}/dict/unk.datgz +0 -0
  13. {static → frontend/public}/dict/unk_char.datgz +0 -0
  14. {static → frontend/public}/dict/unk_compat.datgz +0 -0
  15. {static → frontend/public}/dict/unk_invoke.datgz +0 -0
  16. {static → frontend/public}/dict/unk_map.datgz +0 -0
  17. {static → frontend/public}/dict/unk_pos.datgz +0 -0
  18. {static → frontend/public}/favicon.ico +0 -0
  19. {static → frontend/public}/font/materialdesignicons-webfont.eot +0 -0
  20. {static → frontend/public}/font/materialdesignicons-webfont.ttf +0 -0
  21. {static → frontend/public}/font/materialdesignicons-webfont.woff +0 -0
  22. {static → frontend/public}/font/materialdesignicons-webfont.woff2 +0 -0
  23. {static → frontend/public}/font/materialdesignicons-webfont_ie.eot +0 -0
  24. {static → frontend/public}/font/materialdesignicons.min.css +0 -0
  25. {static → frontend/public}/font/roboto.css +0 -0
  26. {static → frontend/public}/font/vuetify.min.css +0 -0
  27. frontend/public/index.html +19 -0
  28. frontend/src/App.vue +383 -0
  29. frontend/src/main.js +12 -0
  30. frontend/src/plugins/vuetify.js +7 -0
  31. frontend/src/router/index.js +18 -0
  32. frontend/vue.config.js +7 -0
  33. frontend/yarn.lock +0 -0
  34. static/css/chunk-vendors.67710748.css +0 -0
  35. static/index.html +0 -1
  36. static/js/app.1cddaf0c.js +0 -1
  37. static/js/chunk-vendors.4a28e83e.js +0 -0
.gitignore CHANGED
@@ -114,3 +114,4 @@ dmypy.json
114
  .pyre/
115
 
116
  .idea/
 
 
114
  .pyre/
115
 
116
  .idea/
117
+ node_modules/
app.py CHANGED
@@ -49,7 +49,7 @@ def gen_lyric(title: str, prompt_text: str):
49
  return title, lyric
50
 
51
 
52
- app = Flask(__name__, static_url_path="", static_folder="static")
53
 
54
 
55
  @app.route('/')
 
49
  return title, lyric
50
 
51
 
52
+ app = Flask(__name__, static_url_path="", static_folder="frontend/dist")
53
 
54
 
55
  @app.route('/')
frontend/README.md ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # lyric-generator
2
+ 歌词生成器网站
frontend/babel.config.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ module.exports = {
2
+ presets: [
3
+ '@vue/cli-plugin-babel/preset'
4
+ ]
5
+ }
frontend/package.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "lyric-generator",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "serve": "vue-cli-service serve",
7
+ "build": "vue-cli-service build",
8
+ "lint": "vue-cli-service lint"
9
+ },
10
+ "dependencies": {
11
+ "core-js": "^3.6.5",
12
+ "kod-cloud-web-deploy": "^1.0.2",
13
+ "kuroshiro": "^1.2.0",
14
+ "kuroshiro-analyzer-kuromoji": "^1.1.0",
15
+ "vue": "^2.6.11",
16
+ "vue-router": "^3.2.0",
17
+ "vuetify": "^2.6.0"
18
+ },
19
+ "devDependencies": {
20
+ "@vue/cli-plugin-babel": "~4.5.9",
21
+ "@vue/cli-plugin-eslint": "~4.5.9",
22
+ "@vue/cli-plugin-router": "~4.5.9",
23
+ "@vue/cli-service": "~4.5.9",
24
+ "axios": "^0.18.0",
25
+ "babel-eslint": "^10.1.0",
26
+ "eslint": "^6.7.2",
27
+ "eslint-plugin-vue": "^6.2.2",
28
+ "sass": "~1.32.0",
29
+ "sass-loader": "^10.0.0",
30
+ "vue-cli-plugin-axios": "~0.0.4",
31
+ "vue-cli-plugin-vuetify": "~2.4.8",
32
+ "vue-template-compiler": "^2.6.11",
33
+ "vuetify-loader": "^1.7.0"
34
+ },
35
+ "eslintConfig": {
36
+ "root": true,
37
+ "env": {
38
+ "node": true
39
+ },
40
+ "extends": [
41
+ "plugin:vue/essential",
42
+ "eslint:recommended"
43
+ ],
44
+ "parserOptions": {
45
+ "parser": "babel-eslint"
46
+ },
47
+ "rules": {}
48
+ },
49
+ "browserslist": [
50
+ "> 1%",
51
+ "last 2 versions",
52
+ "not dead"
53
+ ]
54
+ }
{static → frontend/public}/dict/base.datgz RENAMED
File without changes
{static → frontend/public}/dict/cc.datgz RENAMED
File without changes
{static → frontend/public}/dict/check.datgz RENAMED
File without changes
{static → frontend/public}/dict/tid.datgz RENAMED
File without changes
{static → frontend/public}/dict/tid_map.datgz RENAMED
File without changes
{static → frontend/public}/dict/tid_pos.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk_char.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk_compat.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk_invoke.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk_map.datgz RENAMED
File without changes
{static → frontend/public}/dict/unk_pos.datgz RENAMED
File without changes
{static → frontend/public}/favicon.ico RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons-webfont.eot RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons-webfont.ttf RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons-webfont.woff RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons-webfont.woff2 RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons-webfont_ie.eot RENAMED
File without changes
{static → frontend/public}/font/materialdesignicons.min.css RENAMED
File without changes
{static → frontend/public}/font/roboto.css RENAMED
File without changes
{static → frontend/public}/font/vuetify.min.css RENAMED
File without changes
frontend/public/index.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+ <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8
+ <title>日语歌词生成器</title>
9
+ <link rel="stylesheet" href="font/roboto.css">
10
+ <link rel="stylesheet" href="font/materialdesignicons.min.css">
11
+ </head>
12
+ <body>
13
+ <noscript>
14
+ <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
15
+ </noscript>
16
+ <div id="app"></div>
17
+ <!-- built files will be auto injected -->
18
+ </body>
19
+ </html>
frontend/src/App.vue ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <template>
2
+ <v-app style="overflow: scroll">
3
+ <v-app-bar app dark color="primary">
4
+ <v-toolbar-title>{{i18n.title}}</v-toolbar-title>
5
+ <v-spacer></v-spacer>
6
+ <v-select style="max-width: 10rem" v-model="locale_name" @change="set_locale(locale_name)" :items="['English','Chinese']" prepend-icon="mdi-web" hide-details></v-select>
7
+ <v-btn href="https://github.com/SkyTNT/gpt2-japanese-lyric" icon><v-icon>mdi-github</v-icon></v-btn>
8
+ <v-btn href="https://fab.moe" icon><v-icon>mdi-home</v-icon></v-btn>
9
+ </v-app-bar>
10
+ <v-main>
11
+ <v-container v-if="loading_kuroshiro" style="height:100%;" fluid>
12
+ <div class="py-2 d-flex flex-column justify-center align-center" style="height:100%;">
13
+ <v-progress-circular color="blue" indeterminate></v-progress-circular>
14
+ <label class="py-4 text">{{i18n.loading}}</label>
15
+ </div>
16
+ </v-container>
17
+ <v-row v-if="!loading_kuroshiro" class="mx-3">
18
+ <div class="col-12 offset-0 col-sm-8 offset-sm-2 col-md-8 offset-md-2 col-lg-6 offset-lg-3 col-xl-6 offset-xl-3 mt-8">
19
+ <v-textarea
20
+ v-model="prompt_title"
21
+ :label="i18n.input_title_label"
22
+ :disabled="loading"
23
+ rows="1"
24
+ prepend-icon="mdi-comment"
25
+ :hint="i18n.input_title_hint"
26
+ no-resize
27
+ ></v-textarea>
28
+ <v-textarea
29
+ v-model="prompt_text"
30
+ :label="i18n.input_text_label"
31
+ :disabled="loading"
32
+ rows="2"
33
+ prepend-icon="mdi-comment"
34
+ :hint="i18n.input_text_hint"
35
+ no-resize
36
+ ></v-textarea>
37
+ <v-row>
38
+ <v-checkbox class="col-6" v-model="show_romaji" :disabled="loading" @change="show_type=show_romaji?0:1" :label="i18n.show_romaji"></v-checkbox>
39
+ <v-scroll-x-transition>
40
+ <v-select class="col-6" v-if="show_romaji" v-model="romaji_system" :disabled="loading" :items="romaji_systems" :hint="i18n.romaji_system"></v-select>
41
+ </v-scroll-x-transition>
42
+ </v-row>
43
+ <v-row class="mt-n8">
44
+ <v-checkbox class="col-6" v-model="use_trans" :disabled="loading" @change="show_type=use_trans?1:0" :label="i18n.use_translate"></v-checkbox>
45
+ <v-scroll-x-transition>
46
+ <v-select class="col-6" v-if="use_trans" v-model="trans_target_lang" :disabled="loading" :items="google_supported_languages" :hint="i18n.target_lang"></v-select>
47
+ </v-scroll-x-transition>
48
+ </v-row>
49
+ <v-btn color="primary" class="mb-10" elevation="5" @click="do_gen(0)" :loading="loading" text block large tile>{{i18n.generate}}</v-btn>
50
+ <v-expand-transition>
51
+ <v-simple-table v-if="lyric.length !== 0" class="py-5" dense>
52
+ <template v-slot:default>
53
+ <thead>
54
+ <tr>
55
+ <th>{{i18n.lyric}}<v-btn class="ml-2" elevation="0" @click="copy_lyric('s')" fab x-small><v-icon>mdi-content-copy</v-icon></v-btn></th>
56
+ <v-scroll-x-transition>
57
+ <th v-if="use_trans||show_romaji">
58
+ <span v-if="show_romaji&&!use_trans">{{i18n.romaji}}</span>
59
+ <span v-if="!show_romaji&&use_trans">{{i18n.translation}}</span>
60
+ <v-btn v-if="use_trans&&show_romaji" class="mr-n2" elevation="0" @click="show_type=show_type===0?1:0" text small>
61
+ <span v-if="show_romaji" :class="{'grey--text':show_type===1}">{{i18n.romaji_s}}</span>/<span v-if="use_trans" :class="{'grey--text':show_type===0}">{{i18n.translation_s}}</span>
62
+ </v-btn>
63
+ <v-btn class="ml-2" elevation="0" @click="copy_lyric(show_type===0?'r':'t')" fab x-small><v-icon>mdi-content-copy</v-icon></v-btn>
64
+ </th>
65
+ </v-scroll-x-transition>
66
+ </tr>
67
+ </thead>
68
+ <tbody style="word-break: break-word; word-wrap:break-word;">
69
+ <tr v-for="(item, idx) in lyric" :key="idx" @mouseenter="hover=idx" @mouseleave="hover=-1">
70
+ <td :class="{'text-h6': idx===0, 'text-center': !item.is_lyric}">
71
+ {{item.s}}
72
+ <v-scroll-x-transition v-if="tts_support">
73
+ <v-btn v-if="!tts_loading&&item.s!==''&&(speaking===idx||(speaking===-1&&hover===idx))" :class="{'mr-n9':true,'blue--text':speaking===idx}" icon small @click="ja_tts(idx)">
74
+ <v-icon>mdi-volume-high</v-icon>
75
+ </v-btn>
76
+ </v-scroll-x-transition >
77
+ <v-progress-circular v-if="tts_support&&speaking===idx&&tts_loading" class="mr-n9" indeterminate size="20" width="2" color="primary"></v-progress-circular>
78
+ </td>
79
+ <v-scroll-x-transition>
80
+ <td v-if="use_trans||show_romaji" :class="{'text-center': !item.is_lyric}">{{show_type===0?item.r:item.t}}</td>
81
+ </v-scroll-x-transition>
82
+ </tr>
83
+ </tbody>
84
+ </template>
85
+ </v-simple-table>
86
+ </v-expand-transition>
87
+ </div>
88
+ </v-row>
89
+ <v-snackbar dark v-model="snackbar" :timeout="2000">
90
+ {{ snackbar_msg }}
91
+ <template v-slot:action="{ attrs }">
92
+ <v-btn color="blue" text v-bind="attrs" @click="snackbar = false">
93
+ Close
94
+ </v-btn>
95
+ </template>
96
+ </v-snackbar>
97
+ </v-main>
98
+ <v-footer>
99
+ <v-row class="ma-0">
100
+ <div class="text-center caption col-12 pa-0">{{i18n.footer}}</div>
101
+ <div class="text-center caption col-12 pa-0">© 2022 SkyTNT</div>
102
+ </v-row>
103
+ </v-footer>
104
+ </v-app>
105
+ </template>
106
+
107
+ <style lang="scss">
108
+ </style>
109
+ <script>
110
+ import axios from 'axios'
111
+ import Kuroshiro from "kuroshiro";
112
+ import KuromojiAnalyzer from "kuroshiro-analyzer-kuromoji";
113
+
114
+ if (!String.prototype.trim) {
115
+ String.prototype.trim = function () {
116
+ return this.triml().trimr();
117
+ }
118
+ String.prototype.triml = function () {
119
+ return this.replace(/^[\s\n\t]+/g, "");
120
+ }
121
+ String.prototype.trimr = function () {
122
+ return this.replace(/[\s\n\t]+$/g, "");
123
+ }
124
+ }
125
+
126
+ function isMobile(){
127
+ return /(iPhone|iPad|iPod|iOS|Android|Windows Phone)/i.test(navigator.userAgent);
128
+ }
129
+
130
+ export default {
131
+ name: "App",
132
+ data:()=>({
133
+ locale_name: "English",
134
+ i18n:{},
135
+ use_trans: false,
136
+ google_supported_languages:['af', 'sq', 'am', 'ar', 'hy', 'az', 'eu', 'be', 'bn', 'bs', 'bg', 'my', 'ca', 'ca', 'ceb', 'co', 'cs', 'da', 'nl', 'nl', 'en', 'eo', 'et', 'fi', 'fr', 'fy', 'ka', 'de', 'gd', 'gd', 'ga', 'gl', 'el', 'gu', 'ht', 'ht', 'ha', 'haw', 'he', 'hi', 'hr', 'hu', 'ig', 'is', 'id', 'it', 'jw', 'ja', 'kn', 'kk', 'km', 'ky', 'ky', 'ko', 'ku', 'lo', 'la', 'lv', 'lt', 'lb', 'lb', 'mk', 'ml', 'mi', 'mr', 'ms', 'mg', 'mt', 'mn', 'ne', 'no', 'ny', 'ny', 'ny', 'or', 'pa', 'pa', 'fa', 'pl', 'pt', 'ps', 'ps', 'ro', 'ro', 'ro', 'ru', 'si', 'si', 'sk', 'sl', 'sm', 'sn', 'sd', 'so', 'st', 'es', 'es', 'sr', 'su', 'sw', 'sv', 'ta', 'te', 'tg', 'tl', 'th', 'tr', 'ug', 'ug', 'uk', 'ur', 'uz', 'vi', 'cy', 'xh', 'yi', 'yo', 'zu', 'zh-CN', 'zh-TW'],
137
+ trans_target_lang:"zh-CN",
138
+ show_romaji:false,
139
+ show_type:0,
140
+ romaji_systems:["nippon","passport","hepburn"],
141
+ romaji_system:"hepburn",
142
+ prompt_title:"桜",
143
+ prompt_text:"",
144
+ loading_kuroshiro:true,
145
+ loading:false,
146
+ lyric:[],
147
+ tts_cache:{},//tts缓存
148
+ tts_loading:false,
149
+ tts_support:false,
150
+ speaking:-1,//正在tts的行数
151
+ hover:-1,//鼠标悬停的行数
152
+ snackbar:false,
153
+ snackbar_msg:"",
154
+ kuroshiro: new Kuroshiro()
155
+ }),
156
+ mounted() {
157
+ this.locale_name = (navigator.language ||navigator.userLanguage)==="zh-CN"?"Chinese":"English"
158
+ if(this.locale_name==="English")
159
+ this.trans_target_lang="en";
160
+ this.set_locale(this.locale_name);
161
+ this.loads();
162
+ },
163
+ methods:{
164
+ set_locale(name){
165
+ let locale = name==="English"?"en":"zh";
166
+ let langs={
167
+ en:{
168
+ title:"Japanese Lyric Generator",
169
+ loading:"Loading",
170
+ input_title_label:"Title (can be empty)",
171
+ input_text_label:"Beginning (can be empty)",
172
+ input_title_hint:"Generate lyric for a given title",
173
+ input_text_hint:"The generator continues with this text",
174
+ show_romaji:"Show romaji",
175
+ romaji_system:"Romaji system",
176
+ use_translate:"Translate",
177
+ target_lang:"Target language",
178
+ generate:"Generate!",
179
+ lyric:"Lyric",
180
+ romaji:"Romaji",
181
+ romaji_s:"R",
182
+ translation:"Translation",
183
+ translation_s:"T",
184
+ footer:"The generated content can be used as you like, please share this site if you like.",
185
+ copy_successful:"Copy successful",
186
+ error:"Error",
187
+ error_network:"Network error",
188
+ error_failed_load_kuromoji:"Failed to load romaji converter",
189
+ error_failed_covert_romaji:"Failed to convert lyric to romaji",
190
+ error_failed_translate:"Failed to translate lyric",
191
+ error_copy:"Copy failed, browser does not support"
192
+ },
193
+ zh:{
194
+ title:"日语歌词生成器",
195
+ loading:"加载中",
196
+ input_title_label:"歌词标题(可不填)",
197
+ input_text_label:"歌词开头(可不填)",
198
+ input_title_hint:"给定标题生成歌词",
199
+ input_text_hint:"生成器以这段文本进行续写",
200
+ show_romaji:"显示罗马音",
201
+ romaji_system:"罗马音系统",
202
+ use_translate:"是否进行翻译",
203
+ target_lang:"目标语言",
204
+ generate:"生成!",
205
+ lyric:"歌词",
206
+ romaji:"罗马音",
207
+ romaji_s:"音",
208
+ translation:"翻译",
209
+ translation_s:"译",
210
+ footer:"生成的内容可以随意使用,喜欢的话就请分享本网站",
211
+ copy_successful:"复制成功",
212
+ error:"错误",
213
+ error_network:"网络错误",
214
+ error_failed_load_kuromoji:"罗马音转换器加载失败",
215
+ error_failed_covert_romaji:"转换罗马音错误",
216
+ error_failed_translate:"翻译出错",
217
+ error_copy:"复制失败,浏览器不支持"
218
+ }
219
+ };
220
+ this.i18n = langs[locale];
221
+ },
222
+ async loads(){
223
+ await this.load_kuroshiro();
224
+ if(!isMobile()){
225
+ eval((await axios.get('https://l2d.fab.moe/js/autoload.js')).data);
226
+ }
227
+ },
228
+ async load_kuroshiro(){
229
+ try {
230
+ await this.kuroshiro.init(new KuromojiAnalyzer({dictPath:"dict/"}));
231
+ }catch (e) {
232
+ this.show_snackbar(this.i18n.error_failed_load_kuromoji+":"+e.message);
233
+ console.log(e);
234
+ }
235
+ this.loading_kuroshiro=false;
236
+ console.log("kuroshiro loaded");
237
+ },
238
+ async do_gen(){
239
+ let prompt_title = this.prompt_title.trim();
240
+ let prompt_text = this.prompt_text.trim();
241
+ this.loading = true;
242
+ this.lyric = [];
243
+ this.tts_cache = {};
244
+
245
+ try {
246
+ let result = await axios.post("gen",
247
+ {title:prompt_title, text:prompt_text})
248
+ let gen_text = `${result.data.title}\n\n${result.data.lyric}`
249
+ let lines = gen_text.split('\n')
250
+ for (let i in lines) {
251
+ let line = lines[i].trim().replace(/ /g, "\u3000")
252
+ this.lyric.push({s: line, r: "", t: "", is_lyric: line!=="---end---"})
253
+ }
254
+ this.lyric[0].is_lyric = false; //title
255
+
256
+ try {
257
+ let romajis = await this.kuroshiro.convert(gen_text, { to: "romaji" ,mode:"spaced",romajiSystem:this.romaji_system})
258
+ romajis = romajis.split('\n')
259
+ for (let i in romajis) {
260
+ this.lyric[i].r = romajis[i]
261
+ }
262
+ }catch (e) {
263
+ this.show_snackbar(this.i18n.error_failed_covert_romaji+":" + e.message)
264
+ }
265
+
266
+ if (this.use_trans) {
267
+ let trans = await this.google_translate(gen_text);
268
+ if (trans !== "") {
269
+ trans = trans.split("\n")
270
+ for (let i in trans) {
271
+ this.lyric[i].t = trans[i].trim().replace(/ /g, "\u3000")
272
+ }
273
+ }
274
+ }
275
+ this.loading = false;
276
+
277
+ } catch (e) {
278
+ console.log(e)
279
+ if(e.message==="Network Error"||e.response === undefined){
280
+ this.show_snackbar(this.i18n.error_network)
281
+ this.loading = false;
282
+ }else {
283
+ this.show_snackbar(this.i18n.error+":" + e.response.data.msg)
284
+ this.loading = false;
285
+ }
286
+ }
287
+
288
+ },
289
+ async google_translate(text){
290
+ let params = {client: "gtx", dt: "t", sl: "ja", tl: this.trans_target_lang, q: text};
291
+ try {
292
+ let result = await axios.get("https://translate.googleapis.com/translate_a/single",{
293
+ params:params
294
+ });
295
+ let out = "";
296
+ let lines = result.data[0];
297
+ for(let i in lines)
298
+ out += lines[i][0];
299
+ return out;
300
+ }catch(e){
301
+ this.show_snackbar(this.i18n.error_failed_translate+":"+e.message);
302
+ }
303
+ return "";
304
+ },
305
+ async ja_tts(line){
306
+ let text = this.lyric[line].s;
307
+ if(this.speaking !== -1||text === ""){
308
+ return;
309
+ }
310
+
311
+ this.speaking = line;
312
+ try{
313
+ let context = new AudioContext();
314
+ let gain = context.createGain();
315
+ gain.gain.value=2;
316
+ if(this.tts_cache[text] === undefined){
317
+ this.tts_loading=true;
318
+ let audio_query = (await axios.post("https://voicevox-skytnt.cloud.okteto.net/audio_query",null,
319
+ {params:{speaker:4,text:text}})).data;
320
+ let wave = (await axios.post("https://voicevox-skytnt.cloud.okteto.net/synthesis",audio_query,
321
+ {params:{speaker:4},responseType:"arraybuffer"})).data;
322
+ this.tts_loading=false;
323
+ this.tts_cache[text] = await context.decodeAudioData(wave);
324
+ }
325
+ let source = context.createBufferSource();
326
+ source.buffer = this.tts_cache[text];
327
+ source.loop = false;
328
+ source.connect(gain);
329
+ gain.connect(context.destination);
330
+ await new Promise((resolve) => {
331
+ source.onended = () => {resolve()}
332
+ source.start(0);//立即播放
333
+ });
334
+ }catch (e) {
335
+ this.show_snackbar(this.i18n.error+":"+e.message)
336
+ }
337
+ this.speaking = -1;
338
+ this.tts_loading=false;//防止网络出错导致tts_loading为true
339
+ },
340
+ copy_lyric(attr_name){
341
+ let text = ""
342
+ for(let i in this.lyric){
343
+ text += this.lyric[i][attr_name] + "\n"
344
+ }
345
+ text = text.trim()
346
+ this.copy(text)
347
+ },
348
+ async copy(text){
349
+ try {
350
+ await navigator.clipboard.writeText(text)
351
+ this.show_snackbar(this.i18n.copy_successful)
352
+ }catch (e) {
353
+ let input = document.createElement('textarea')
354
+ input.style.position = 'fixed'
355
+ input.style.top = '-10000px'
356
+ input.style.zIndex = '-999'
357
+ document.body.appendChild(input)
358
+ console.log('input', input)
359
+ input.value = text
360
+ input.focus()
361
+ input.select()
362
+ try {
363
+ let result = document.execCommand('copy')
364
+ if (!result || result === 'unsuccessful') {
365
+ this.show_snackbar(this.i18n.error_copy)
366
+ } else {
367
+ this.show_snackbar(this.i18n.copy_successful)
368
+ }
369
+ } catch (e) {
370
+ this.show_snackbar(this.i18n.error_copy)
371
+ }finally {
372
+ document.body.removeChild(input)
373
+ }
374
+ }
375
+ },
376
+ show_snackbar(msg){
377
+ this.snackbar=true;
378
+ this.snackbar_msg=msg;
379
+ }
380
+ }
381
+ }
382
+
383
+ </script>
frontend/src/main.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Vue from 'vue'
2
+ import App from './App.vue'
3
+ import vuetify from './plugins/vuetify'
4
+ import router from './router'
5
+
6
+ Vue.config.productionTip = false
7
+
8
+ new Vue({
9
+ vuetify,
10
+ router,
11
+ render: h => h(App)
12
+ }).$mount('#app')
frontend/src/plugins/vuetify.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import Vue from 'vue';
2
+ import Vuetify from 'vuetify/lib/framework';
3
+
4
+ Vue.use(Vuetify);
5
+
6
+ export default new Vuetify({
7
+ });
frontend/src/router/index.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Vue from 'vue'
2
+ import VueRouter from 'vue-router'
3
+
4
+ Vue.use(VueRouter)
5
+
6
+ const routes = [
7
+ // {
8
+ // path: '/',
9
+ // name: 'Home',
10
+ // component: Home
11
+ // }
12
+ ]
13
+
14
+ const router = new VueRouter({
15
+ routes
16
+ })
17
+
18
+ export default router
frontend/vue.config.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ transpileDependencies: [
3
+ 'vuetify'
4
+ ],
5
+ publicPath: '',
6
+ productionSourceMap: false
7
+ }
frontend/yarn.lock ADDED
The diff for this file is too large to render. See raw diff
 
static/css/chunk-vendors.67710748.css DELETED
The diff for this file is too large to render. See raw diff
 
static/index.html DELETED
@@ -1 +0,0 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>日语歌词生成器</title><link rel="stylesheet" href="font/roboto.css"><link rel="stylesheet" href="font/materialdesignicons.min.css"><link href="css/chunk-vendors.67710748.css" rel="preload" as="style"><link href="js/app.1cddaf0c.js" rel="preload" as="script"><link href="js/chunk-vendors.4a28e83e.js" rel="preload" as="script"><link href="css/chunk-vendors.67710748.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but lyric-generator doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.4a28e83e.js"></script><script src="js/app.1cddaf0c.js"></script></body></html>
 
 
static/js/app.1cddaf0c.js DELETED
@@ -1 +0,0 @@
1
- (function(t){function e(e){for(var a,s,i=e[0],l=e[1],c=e[2],p=0,_=[];p<i.length;p++)s=i[p],Object.prototype.hasOwnProperty.call(n,s)&&n[s]&&_.push(n[s][0]),n[s]=0;for(a in l)Object.prototype.hasOwnProperty.call(l,a)&&(t[a]=l[a]);u&&u(e);while(_.length)_.shift()();return o.push.apply(o,c||[]),r()}function r(){for(var t,e=0;e<o.length;e++){for(var r=o[e],a=!0,i=1;i<r.length;i++){var l=r[i];0!==n[l]&&(a=!1)}a&&(o.splice(e--,1),t=s(s.s=r[0]))}return t}var a={},n={app:0},o=[];function s(e){if(a[e])return a[e].exports;var r=a[e]={i:e,l:!1,exports:{}};return t[e].call(r.exports,r,r.exports,s),r.l=!0,r.exports}s.m=t,s.c=a,s.d=function(t,e,r){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},s.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)s.d(r,a,function(e){return t[e]}.bind(null,a));return r},s.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="";var i=window["webpackJsonp"]=window["webpackJsonp"]||[],l=i.push.bind(i);i.push=e,i=i.slice();for(var c=0;c<i.length;c++)e(i[c]);var u=l;o.push([0,"chunk-vendors"]),r()})({0:function(t,e,r){t.exports=r("56d7")},"56d7":function(t,e,r){"use strict";r.r(e);r("e260"),r("e6cf"),r("cca6"),r("a79d");var a=r("2b0e"),n=function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("v-app",[r("v-app-bar",{attrs:{app:"",dark:"",color:"primary"}},[r("v-toolbar-title",[t._v(t._s(t.i18n.title))]),r("v-spacer"),r("v-select",{staticStyle:{"max-width":"10rem"},attrs:{items:["English","Chinese"],"prepend-icon":"mdi-web","hide-details":""},on:{change:function(e){return t.set_locale(t.locale_name)}},model:{value:t.locale_name,callback:function(e){t.locale_name=e},expression:"locale_name"}}),r("v-btn",{attrs:{href:"https://github.com/SkyTNT/gpt2-japanese-lyric",icon:""}},[r("v-icon",[t._v("mdi-github")])],1),r("v-btn",{attrs:{href:"https://fab.moe",icon:""}},[r("v-icon",[t._v("mdi-home")])],1)],1),r("v-main",[t.loading_kuroshiro?r("v-container",{staticStyle:{height:"100%"},attrs:{fluid:""}},[r("div",{staticClass:"py-2 d-flex flex-column justify-center align-center",staticStyle:{height:"100%"}},[r("v-progress-circular",{attrs:{color:"blue",indeterminate:""}}),r("label",{staticClass:"py-4 text"},[t._v(t._s(t.i18n.loading))])],1)]):t._e(),t.loading_kuroshiro?t._e():r("v-row",{staticClass:"mx-3"},[r("div",{staticClass:"col-12 offset-0 col-sm-8 offset-sm-2 col-md-8 offset-md-2 col-lg-6 offset-lg-3 col-xl-6 offset-xl-3 mt-8"},[r("v-textarea",{attrs:{label:t.i18n.input_title_label,disabled:t.loading,rows:"1","prepend-icon":"mdi-comment",hint:t.i18n.input_title_hint,"no-resize":""},model:{value:t.prompt_title,callback:function(e){t.prompt_title=e},expression:"prompt_title"}}),r("v-textarea",{attrs:{label:t.i18n.input_text_label,disabled:t.loading,rows:"2","prepend-icon":"mdi-comment",hint:t.i18n.input_text_hint,"no-resize":""},model:{value:t.prompt_text,callback:function(e){t.prompt_text=e},expression:"prompt_text"}}),r("v-row",[r("v-checkbox",{staticClass:"col-6",attrs:{disabled:t.loading,label:t.i18n.show_romaji},on:{change:function(e){t.show_type=t.show_romaji?0:1}},model:{value:t.show_romaji,callback:function(e){t.show_romaji=e},expression:"show_romaji"}}),r("v-scroll-x-transition",[t.show_romaji?r("v-select",{staticClass:"col-6",attrs:{disabled:t.loading,items:t.romaji_systems,hint:t.i18n.romaji_system},model:{value:t.romaji_system,callback:function(e){t.romaji_system=e},expression:"romaji_system"}}):t._e()],1)],1),r("v-row",{staticClass:"mt-n8"},[r("v-checkbox",{staticClass:"col-6",attrs:{disabled:t.loading,label:t.i18n.use_translate},on:{change:function(e){t.show_type=t.use_trans?1:0}},model:{value:t.use_trans,callback:function(e){t.use_trans=e},expression:"use_trans"}}),r("v-scroll-x-transition",[t.use_trans?r("v-select",{staticClass:"col-6",attrs:{disabled:t.loading,items:t.google_supported_languages,hint:t.i18n.target_lang},model:{value:t.trans_target_lang,callback:function(e){t.trans_target_lang=e},expression:"trans_target_lang"}}):t._e()],1)],1),r("v-btn",{staticClass:"mb-10",attrs:{color:"primary",elevation:"5",loading:t.loading,text:"",block:"",large:"",tile:""},on:{click:function(e){return t.do_gen(0)}}},[t._v(t._s(t.i18n.generate))]),r("v-expand-transition",[0!==t.lyric.length?r("v-simple-table",{staticClass:"py-5",attrs:{dense:""},scopedSlots:t._u([{key:"default",fn:function(){return[r("thead",[r("tr",[r("th",[t._v(t._s(t.i18n.lyric)),r("v-btn",{staticClass:"ml-2",attrs:{elevation:"0",fab:"","x-small":""},on:{click:function(e){return t.copy_lyric("s")}}},[r("v-icon",[t._v("mdi-content-copy")])],1)],1),r("v-scroll-x-transition",[t.use_trans||t.show_romaji?r("th",[t.show_romaji&&!t.use_trans?r("span",[t._v(t._s(t.i18n.romaji))]):t._e(),!t.show_romaji&&t.use_trans?r("span",[t._v(t._s(t.i18n.translation))]):t._e(),t.use_trans&&t.show_romaji?r("v-btn",{staticClass:"mr-n2",attrs:{elevation:"0",text:"",small:""},on:{click:function(e){t.show_type=0===t.show_type?1:0}}},[t.show_romaji?r("span",{class:{"grey--text":1===t.show_type}},[t._v(t._s(t.i18n.romaji_s))]):t._e(),t._v("/"),t.use_trans?r("span",{class:{"grey--text":0===t.show_type}},[t._v(t._s(t.i18n.translation_s))]):t._e()]):t._e(),r("v-btn",{staticClass:"ml-2",attrs:{elevation:"0",fab:"","x-small":""},on:{click:function(e){return t.copy_lyric(0===t.show_type?"r":"t")}}},[r("v-icon",[t._v("mdi-content-copy")])],1)],1):t._e()])],1)]),r("tbody",{staticStyle:{"word-break":"break-word","word-wrap":"break-word"}},t._l(t.lyric,(function(e,a){return r("tr",{key:a,on:{mouseenter:function(e){t.hover=a},mouseleave:function(e){t.hover=-1}}},[r("td",{class:{"text-h6":0===a,"text-center":!e.is_lyric}},[t._v(" "+t._s(e.s)+" "),t.tts_support?r("v-scroll-x-transition",[t.tts_loading||""===e.s||t.speaking!==a&&(-1!==t.speaking||t.hover!==a)?t._e():r("v-btn",{class:{"mr-n9":!0,"blue--text":t.speaking===a},attrs:{icon:"",small:""},on:{click:function(e){return t.ja_tts(a)}}},[r("v-icon",[t._v("mdi-volume-high")])],1)],1):t._e(),t.tts_support&&t.speaking===a&&t.tts_loading?r("v-progress-circular",{staticClass:"mr-n9",attrs:{indeterminate:"",size:"20",width:"2",color:"primary"}}):t._e()],1),r("v-scroll-x-transition",[t.use_trans||t.show_romaji?r("td",{class:{"text-center":!e.is_lyric}},[t._v(t._s(0===t.show_type?e.r:e.t))]):t._e()])],1)})),0)]},proxy:!0}],null,!1,3397400449)}):t._e()],1)],1)]),r("v-snackbar",{attrs:{dark:"",timeout:2e3},scopedSlots:t._u([{key:"action",fn:function(e){var a=e.attrs;return[r("v-btn",t._b({attrs:{color:"blue",text:""},on:{click:function(e){t.snackbar=!1}}},"v-btn",a,!1),[t._v(" Close ")])]}}]),model:{value:t.snackbar,callback:function(e){t.snackbar=e},expression:"snackbar"}},[t._v(" "+t._s(t.snackbar_msg)+" ")])],1),r("v-footer",[r("v-row",{staticClass:"ma-0"},[r("div",{staticClass:"text-center caption col-12 pa-0"},[t._v(t._s(t.i18n.footer))]),r("div",{staticClass:"text-center caption col-12 pa-0"},[t._v("© 2022 SkyTNT")])])],1)],1)},o=[],s=r("1da1"),i=(r("96cf"),r("498a"),r("ac1f"),r("5319"),r("00b4"),r("99af"),r("1276"),r("d3b7"),r("bc3a")),l=r.n(i),c=r("1539"),u=r("856a");function p(){return/(iPhone|iPad|iPod|iOS|Android|Windows Phone)/i.test(navigator.userAgent)}String.prototype.trim||(String.prototype.trim=function(){return this.triml().trimr()},String.prototype.triml=function(){return this.replace(/^[\s\n\t]+/g,"")},String.prototype.trimr=function(){return this.replace(/[\s\n\t]+$/g,"")});var _={name:"App",data:function(){return{locale_name:"English",i18n:{},use_trans:!1,google_supported_languages:["af","sq","am","ar","hy","az","eu","be","bn","bs","bg","my","ca","ca","ceb","co","cs","da","nl","nl","en","eo","et","fi","fr","fy","ka","de","gd","gd","ga","gl","el","gu","ht","ht","ha","haw","he","hi","hr","hu","ig","is","id","it","jw","ja","kn","kk","km","ky","ky","ko","ku","lo","la","lv","lt","lb","lb","mk","ml","mi","mr","ms","mg","mt","mn","ne","no","ny","ny","ny","or","pa","pa","fa","pl","pt","ps","ps","ro","ro","ro","ru","si","si","sk","sl","sm","sn","sd","so","st","es","es","sr","su","sw","sv","ta","te","tg","tl","th","tr","ug","ug","uk","ur","uz","vi","cy","xh","yi","yo","zu","zh-CN","zh-TW"],trans_target_lang:"zh-CN",show_romaji:!1,show_type:0,romaji_systems:["nippon","passport","hepburn"],romaji_system:"hepburn",prompt_title:"桜",prompt_text:"",loading_kuroshiro:!0,loading:!1,lyric:[],tts_cache:{},tts_loading:!1,tts_support:!1,speaking:-1,hover:-1,snackbar:!1,snackbar_msg:"",kuroshiro:new c["a"]}},mounted:function(){this.locale_name="zh-CN"===(navigator.language||navigator.userLanguage)?"Chinese":"English","English"===this.locale_name&&(this.trans_target_lang="en"),this.set_locale(this.locale_name),this.loads()},methods:{set_locale:function(t){var e="English"===t?"en":"zh",r={en:{title:"Japanese Lyric Generator",loading:"Loading",input_title_label:"Title (can be empty)",input_text_label:"Beginning (can be empty)",input_title_hint:"Generate lyric for a given title",input_text_hint:"The generator continues with this text",show_romaji:"Show romaji",romaji_system:"Romaji system",use_translate:"Translate",target_lang:"Target language",generate:"Generate!",lyric:"Lyric",romaji:"Romaji",romaji_s:"R",translation:"Translation",translation_s:"T",footer:"The generated content can be used as you like, please share this site if you like.",copy_successful:"Copy successful",error:"Error",error_network:"Network error",error_failed_load_kuromoji:"Failed to load romaji converter",error_failed_covert_romaji:"Failed to convert lyric to romaji",error_failed_translate:"Failed to translate lyric",error_copy:"Copy failed, browser does not support"},zh:{title:"日语歌词生成器",loading:"加载中",input_title_label:"歌词标题(可不填)",input_text_label:"歌词开头(可不填)",input_title_hint:"给定标题生成歌词",input_text_hint:"生成器��这段文本进行续写",show_romaji:"显示罗马音",romaji_system:"罗马音系统",use_translate:"是否进行翻译",target_lang:"目标语言",generate:"生成!",lyric:"歌词",romaji:"罗马音",romaji_s:"音",translation:"翻译",translation_s:"译",footer:"生成的内容可以随意使用,喜欢的话就请分享本网站",copy_successful:"复制成功",error:"错误",error_network:"网络错误",error_failed_load_kuromoji:"罗马音转换器加载失败",error_failed_covert_romaji:"转换罗马音错误",error_failed_translate:"翻译出错",error_copy:"复制失败,浏览器不支持"}};this.i18n=r[e]},loads:function(){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function e(){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,t.load_kuroshiro();case 2:if(p()){e.next=8;break}return e.t0=eval,e.next=6,l.a.get("https://l2d.fab.moe/js/autoload.js");case 6:e.t1=e.sent.data,(0,e.t0)(e.t1);case 8:case"end":return e.stop()}}),e)})))()},load_kuroshiro:function(){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function e(){return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return e.prev=0,e.next=3,t.kuroshiro.init(new u["a"]({dictPath:"dict/"}));case 3:e.next=9;break;case 5:e.prev=5,e.t0=e["catch"](0),t.show_snackbar(t.i18n.error_failed_load_kuromoji+":"+e.t0.message),console.log(e.t0);case 9:t.loading_kuroshiro=!1,console.log("kuroshiro loaded");case 11:case"end":return e.stop()}}),e,null,[[0,5]])})))()},do_gen:function(){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function e(){var r,a,n,o,s,i,c,u,p,_,m;return regeneratorRuntime.wrap((function(e){while(1)switch(e.prev=e.next){case 0:return r=t.prompt_title.trim(),a=t.prompt_text.trim(),t.loading=!0,t.lyric=[],t.tts_cache={},e.prev=5,e.next=8,l.a.post("gen",{title:r,text:a});case 8:for(i in n=e.sent,o="".concat(n.data.title,"\n\n").concat(n.data.lyric),s=o.split("\n"),s)c=s[i].trim().replace(/ /g," "),t.lyric.push({s:c,r:"",t:"",is_lyric:"---end---"!==c});return t.lyric[0].is_lyric=!1,e.prev=13,e.next=16,t.kuroshiro.convert(o,{to:"romaji",mode:"spaced",romajiSystem:t.romaji_system});case 16:for(p in u=e.sent,u=u.split("\n"),u)t.lyric[p].r=u[p];e.next=24;break;case 21:e.prev=21,e.t0=e["catch"](13),t.show_snackbar(t.i18n.error_failed_covert_romaji+":"+e.t0.message);case 24:if(!t.use_trans){e.next=29;break}return e.next=27,t.google_translate(o);case 27:if(_=e.sent,""!==_)for(m in _=_.split("\n"),_)t.lyric[m].t=_[m].trim().replace(/ /g," ");case 29:t.loading=!1,e.next=36;break;case 32:e.prev=32,e.t1=e["catch"](5),console.log(e.t1),"Network Error"===e.t1.message||void 0===e.t1.response?(t.show_snackbar(t.i18n.error_network),t.loading=!1):(t.show_snackbar(t.i18n.error+":"+e.t1.response.data.msg),t.loading=!1);case 36:case"end":return e.stop()}}),e,null,[[5,32],[13,21]])})))()},google_translate:function(t){var e=this;return Object(s["a"])(regeneratorRuntime.mark((function r(){var a,n,o,s,i;return regeneratorRuntime.wrap((function(r){while(1)switch(r.prev=r.next){case 0:return a={client:"gtx",dt:"t",sl:"ja",tl:e.trans_target_lang,q:t},r.prev=1,r.next=4,l.a.get("https://translate.googleapis.com/translate_a/single",{params:a});case 4:for(i in n=r.sent,o="",s=n.data[0],s)o+=s[i][0];return r.abrupt("return",o);case 11:r.prev=11,r.t0=r["catch"](1),e.show_snackbar(e.i18n.error_failed_translate+":"+r.t0.message);case 14:return r.abrupt("return","");case 15:case"end":return r.stop()}}),r,null,[[1,11]])})))()},ja_tts:function(t){var e=this;return Object(s["a"])(regeneratorRuntime.mark((function r(){var a,n,o,s,i,c;return regeneratorRuntime.wrap((function(r){while(1)switch(r.prev=r.next){case 0:if(a=e.lyric[t].s,-1===e.speaking&&""!==a){r.next=3;break}return r.abrupt("return");case 3:if(e.speaking=t,r.prev=4,n=new AudioContext,o=n.createGain(),o.gain.value=2,void 0!==e.tts_cache[a]){r.next=20;break}return e.tts_loading=!0,r.next=12,l.a.post("https://voicevox-skytnt.cloud.okteto.net/audio_query",null,{params:{speaker:4,text:a}});case 12:return s=r.sent.data,r.next=15,l.a.post("https://voicevox-skytnt.cloud.okteto.net/synthesis",s,{params:{speaker:4},responseType:"arraybuffer"});case 15:return i=r.sent.data,e.tts_loading=!1,r.next=19,n.decodeAudioData(i);case 19:e.tts_cache[a]=r.sent;case 20:return c=n.createBufferSource(),c.buffer=e.tts_cache[a],c.loop=!1,c.connect(o),o.connect(n.destination),r.next=27,new Promise((function(t){c.onended=function(){t()},c.start(0)}));case 27:r.next=32;break;case 29:r.prev=29,r.t0=r["catch"](4),e.show_snackbar(e.i18n.error+":"+r.t0.message);case 32:e.speaking=-1,e.tts_loading=!1;case 34:case"end":return r.stop()}}),r,null,[[4,29]])})))()},copy_lyric:function(t){var e="";for(var r in this.lyric)e+=this.lyric[r][t]+"\n";e=e.trim(),this.copy(e)},copy:function(t){var e=this;return Object(s["a"])(regeneratorRuntime.mark((function r(){var a,n;return regeneratorRuntime.wrap((function(r){while(1)switch(r.prev=r.next){case 0:return r.prev=0,r.next=3,navigator.clipboard.writeText(t);case 3:e.show_snackbar(e.i18n.copy_successful),r.next=18;break;case 6:r.prev=6,r.t0=r["catch"](0),a=document.createElement("textarea"),a.style.position="fixed",a.style.top="-10000px",a.style.zIndex="-999",document.body.appendChild(a),console.log("input",a),a.value=t,a.focus(),a.select();try{n=document.execCommand("copy"),n&&"unsuccessful"!==n?e.show_snackbar(e.i18n.copy_successful):e.show_snackbar(e.i18n.error_copy)}catch(o){e.show_snackbar(e.i18n.error_copy)}finally{document.body.removeChild(a)}case 18:case"end":return r.stop()}}),r,null,[[0,6]])})))()},show_snackbar:function(t){this.snackbar=!0,this.snackbar_msg=t}}},m=_,d=r("2877"),h=r("6544"),g=r.n(h),f=r("7496"),v=r("40dc"),b=r("8336"),y=r("ac7c"),k=r("a523"),x=r("0789"),w=r("553a"),j=r("132d"),C=r("f6c4"),S=r("490a"),T=r("0fd9"),O=r("b974"),V=r("1f4f"),R=r("2db4"),P=r("2fa4"),z=r("a844"),E=r("2a7f"),A=Object(d["a"])(m,n,o,!1,null,null,null),N=A.exports;g()(A,{VApp:f["a"],VAppBar:v["a"],VBtn:b["a"],VCheckbox:y["a"],VContainer:k["a"],VExpandTransition:x["a"],VFooter:w["a"],VIcon:j["a"],VMain:C["a"],VProgressCircular:S["a"],VRow:T["a"],VScrollXTransition:x["d"],VSelect:O["a"],VSimpleTable:V["a"],VSnackbar:R["a"],VSpacer:P["a"],VTextarea:z["a"],VToolbarTitle:E["a"]});var M=r("f309");a["a"].use(M["a"]);var B=new M["a"]({}),F=r("8c4f");a["a"].use(F["a"]);var G=[],L=new F["a"]({routes:G}),q=L;a["a"].config.productionTip=!1,new a["a"]({vuetify:B,router:q,render:function(t){return t(N)}}).$mount("#app")}});
 
 
static/js/chunk-vendors.4a28e83e.js DELETED
The diff for this file is too large to render. See raw diff