Spaces:
Running
Running
gemini-stars: 旁白文案、TTS 音频与时间轴(step 2)
Browse files- gemini-stars/README.md +1 -1
- gemini-stars/audio/v01.mp3 +0 -0
- gemini-stars/audio/v02.mp3 +0 -0
- gemini-stars/audio/v03.mp3 +0 -0
- gemini-stars/audio/v04.mp3 +0 -0
- gemini-stars/audio/v05.mp3 +0 -0
- gemini-stars/audio/v06.mp3 +0 -0
- gemini-stars/audio/v07.mp3 +0 -0
- gemini-stars/audio/v08.mp3 +0 -0
- gemini-stars/audio/v09.mp3 +0 -0
- gemini-stars/audio/v10.mp3 +0 -0
- gemini-stars/audio/v11.mp3 +0 -0
- gemini-stars/audio/v12.mp3 +0 -0
- gemini-stars/audio/v13.mp3 +0 -0
- gemini-stars/audio/v14.mp3 +0 -0
- gemini-stars/audio/v15.mp3 +0 -0
- gemini-stars/audio/v16.mp3 +0 -0
- gemini-stars/audio/v17.mp3 +0 -0
- gemini-stars/audio/v18.mp3 +0 -0
- gemini-stars/audio/v19.mp3 +0 -0
- gemini-stars/audio/v20.mp3 +0 -0
- gemini-stars/audio/v21.mp3 +0 -0
- gemini-stars/audio/v22.mp3 +0 -0
- gemini-stars/audio/v23.mp3 +0 -0
- gemini-stars/audio/v24.mp3 +0 -0
- gemini-stars/audio/v25.mp3 +0 -0
- gemini-stars/audio/v26.mp3 +0 -0
- gemini-stars/audio/v27.mp3 +0 -0
- gemini-stars/audio/v28.mp3 +0 -0
- gemini-stars/audio/v29.mp3 +0 -0
- gemini-stars/timeline.js +243 -0
- gemini-stars/tools/make_voice.py +85 -0
gemini-stars/README.md
CHANGED
|
@@ -59,7 +59,7 @@ gemini-stars/
|
|
| 59 |
## 4. 步骤与进度看板
|
| 60 |
|
| 61 |
- [x] Step 1:撰写本计划(本文件)并推送
|
| 62 |
-
- [
|
| 63 |
- [ ] Step 3:场景动画引擎与全部场景(横/竖屏自适应),推送
|
| 64 |
- [ ] Step 4:配乐与音效合成、混音、播放器,推送
|
| 65 |
- [ ] Step 5:MP4 本地导出(24/30/60fps,横/竖屏),推送
|
|
|
|
| 59 |
## 4. 步骤与进度看板
|
| 60 |
|
| 61 |
- [x] Step 1:撰写本计划(本文件)并推送
|
| 62 |
+
- [x] Step 2:撰写旁白文案,生成 TTS 音频与 `timeline.js`,推送
|
| 63 |
- [ ] Step 3:场景动画引擎与全部场景(横/竖屏自适应),推送
|
| 64 |
- [ ] Step 4:配乐与音效合成、混音、播放器,推送
|
| 65 |
- [ ] Step 5:MP4 本地导出(24/30/60fps,横/竖屏),推送
|
gemini-stars/audio/v01.mp3
ADDED
|
Binary file (42.2 kB). View file
|
|
|
gemini-stars/audio/v02.mp3
ADDED
|
Binary file (29.1 kB). View file
|
|
|
gemini-stars/audio/v03.mp3
ADDED
|
Binary file (33 kB). View file
|
|
|
gemini-stars/audio/v04.mp3
ADDED
|
Binary file (25.6 kB). View file
|
|
|
gemini-stars/audio/v05.mp3
ADDED
|
Binary file (35.1 kB). View file
|
|
|
gemini-stars/audio/v06.mp3
ADDED
|
Binary file (40.6 kB). View file
|
|
|
gemini-stars/audio/v07.mp3
ADDED
|
Binary file (56.7 kB). View file
|
|
|
gemini-stars/audio/v08.mp3
ADDED
|
Binary file (51.3 kB). View file
|
|
|
gemini-stars/audio/v09.mp3
ADDED
|
Binary file (22.6 kB). View file
|
|
|
gemini-stars/audio/v10.mp3
ADDED
|
Binary file (38.9 kB). View file
|
|
|
gemini-stars/audio/v11.mp3
ADDED
|
Binary file (62.8 kB). View file
|
|
|
gemini-stars/audio/v12.mp3
ADDED
|
Binary file (21.7 kB). View file
|
|
|
gemini-stars/audio/v13.mp3
ADDED
|
Binary file (42.9 kB). View file
|
|
|
gemini-stars/audio/v14.mp3
ADDED
|
Binary file (58.5 kB). View file
|
|
|
gemini-stars/audio/v15.mp3
ADDED
|
Binary file (36.3 kB). View file
|
|
|
gemini-stars/audio/v16.mp3
ADDED
|
Binary file (42.3 kB). View file
|
|
|
gemini-stars/audio/v17.mp3
ADDED
|
Binary file (36.1 kB). View file
|
|
|
gemini-stars/audio/v18.mp3
ADDED
|
Binary file (41.2 kB). View file
|
|
|
gemini-stars/audio/v19.mp3
ADDED
|
Binary file (33.6 kB). View file
|
|
|
gemini-stars/audio/v20.mp3
ADDED
|
Binary file (42.5 kB). View file
|
|
|
gemini-stars/audio/v21.mp3
ADDED
|
Binary file (24.5 kB). View file
|
|
|
gemini-stars/audio/v22.mp3
ADDED
|
Binary file (31.8 kB). View file
|
|
|
gemini-stars/audio/v23.mp3
ADDED
|
Binary file (36.3 kB). View file
|
|
|
gemini-stars/audio/v24.mp3
ADDED
|
Binary file (51.8 kB). View file
|
|
|
gemini-stars/audio/v25.mp3
ADDED
|
Binary file (43.9 kB). View file
|
|
|
gemini-stars/audio/v26.mp3
ADDED
|
Binary file (46.1 kB). View file
|
|
|
gemini-stars/audio/v27.mp3
ADDED
|
Binary file (40.3 kB). View file
|
|
|
gemini-stars/audio/v28.mp3
ADDED
|
Binary file (33 kB). View file
|
|
|
gemini-stars/audio/v29.mp3
ADDED
|
Binary file (21.3 kB). View file
|
|
|
gemini-stars/timeline.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// 由 tools/make_voice.py 自动生成,请勿手改
|
| 2 |
+
export const TIMELINE = {
|
| 3 |
+
"duration": 214.32,
|
| 4 |
+
"scenes": [
|
| 5 |
+
{
|
| 6 |
+
"id": "intro",
|
| 7 |
+
"start": 0,
|
| 8 |
+
"lines": [
|
| 9 |
+
{
|
| 10 |
+
"file": "audio/v01.mp3",
|
| 11 |
+
"text": "冬天的夜里,如果你抬头望向东方,会看到两颗明亮的星星,肩并着肩。",
|
| 12 |
+
"start": 2.6,
|
| 13 |
+
"end": 9.63
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"file": "audio/v02.mp3",
|
| 17 |
+
"text": "它们就像一对形影不离的兄弟——这,就是双子座。",
|
| 18 |
+
"start": 10.01,
|
| 19 |
+
"end": 14.86
|
| 20 |
+
}
|
| 21 |
+
],
|
| 22 |
+
"end": 15.64
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"id": "find",
|
| 26 |
+
"start": 15.64,
|
| 27 |
+
"lines": [
|
| 28 |
+
{
|
| 29 |
+
"file": "audio/v03.mp3",
|
| 30 |
+
"text": "想找到它很简单。先找到猎户座腰带上的三颗星,",
|
| 31 |
+
"start": 16.24,
|
| 32 |
+
"end": 21.74
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"file": "audio/v04.mp3",
|
| 36 |
+
"text": "再顺着猎户座的身体,向东北方向望过去。",
|
| 37 |
+
"start": 22.12,
|
| 38 |
+
"end": 26.39
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"file": "audio/v05.mp3",
|
| 42 |
+
"text": "那两颗挨得很近的亮星,就是双子的头:北河二和北河三。",
|
| 43 |
+
"start": 26.77,
|
| 44 |
+
"end": 32.63
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"file": "audio/v06.mp3",
|
| 48 |
+
"text": "从它们向下延伸出两串星,像两个手拉着手的小人,站在银河岸边。",
|
| 49 |
+
"start": 33.01,
|
| 50 |
+
"end": 39.78
|
| 51 |
+
}
|
| 52 |
+
],
|
| 53 |
+
"end": 40.64
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"id": "myth",
|
| 57 |
+
"start": 40.64,
|
| 58 |
+
"lines": [
|
| 59 |
+
{
|
| 60 |
+
"file": "audio/v07.mp3",
|
| 61 |
+
"text": "在古希腊神话里,他们是一对孪生兄弟:哥哥卡斯托尔擅长驯马,弟弟波吕克斯是拳击高手。",
|
| 62 |
+
"start": 41.36,
|
| 63 |
+
"end": 50.82
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"file": "audio/v08.mp3",
|
| 67 |
+
"text": "可他们的命运并不相同:卡斯托尔是凡人,而波吕克斯是宙斯之子,拥有不朽的生命。",
|
| 68 |
+
"start": 51.2,
|
| 69 |
+
"end": 59.74
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"file": "audio/v09.mp3",
|
| 73 |
+
"text": "一次争斗中,卡斯托尔中箭身亡。",
|
| 74 |
+
"start": 60.12,
|
| 75 |
+
"end": 63.89
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"file": "audio/v10.mp3",
|
| 79 |
+
"text": "波吕克斯悲痛万分,他请求宙斯:把我的不朽,分一半给哥哥吧。",
|
| 80 |
+
"start": 64.27,
|
| 81 |
+
"end": 70.75
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"file": "audio/v11.mp3",
|
| 85 |
+
"text": "宙斯被打动了。从此兄弟俩一天在天上,一天在冥界,永远不再分开,并肩化作了夜空中的双子座。",
|
| 86 |
+
"start": 71.13,
|
| 87 |
+
"end": 81.59
|
| 88 |
+
}
|
| 89 |
+
],
|
| 90 |
+
"end": 82.45
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"id": "castor",
|
| 94 |
+
"start": 82.45,
|
| 95 |
+
"lines": [
|
| 96 |
+
{
|
| 97 |
+
"file": "audio/v12.mp3",
|
| 98 |
+
"text": "神话很浪漫,而科学更惊奇。",
|
| 99 |
+
"start": 83.17,
|
| 100 |
+
"end": 86.79
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"file": "audio/v13.mp3",
|
| 104 |
+
"text": "哥哥北河二,用肉眼看只是一颗星,可在望远镜里,它分成了好几颗。",
|
| 105 |
+
"start": 87.17,
|
| 106 |
+
"end": 94.32
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"file": "audio/v14.mp3",
|
| 110 |
+
"text": "天文学家发现,它其实是六颗恒星组成的大家庭:三对双星彼此绕转,距离我们大约五十一光年。",
|
| 111 |
+
"start": 94.7,
|
| 112 |
+
"end": 104.44
|
| 113 |
+
}
|
| 114 |
+
],
|
| 115 |
+
"end": 105.22
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"id": "pollux",
|
| 119 |
+
"start": 105.22,
|
| 120 |
+
"lines": [
|
| 121 |
+
{
|
| 122 |
+
"file": "audio/v15.mp3",
|
| 123 |
+
"text": "弟弟北河三,是一颗橙色的巨星,距离我们大约三十四光年。",
|
| 124 |
+
"start": 105.82,
|
| 125 |
+
"end": 111.87
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"file": "audio/v16.mp3",
|
| 129 |
+
"text": "有趣的是,它排名叫“三”,却比“二”号哥哥更亮,是整个双子座最亮的星。",
|
| 130 |
+
"start": 112.25,
|
| 131 |
+
"end": 119.31
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"file": "audio/v17.mp3",
|
| 135 |
+
"text": "在它身旁,还有一颗质量至少是木星两倍的行星,默默绕转。",
|
| 136 |
+
"start": 119.69,
|
| 137 |
+
"end": 125.71
|
| 138 |
+
}
|
| 139 |
+
],
|
| 140 |
+
"end": 126.57
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"id": "meteor",
|
| 144 |
+
"start": 126.57,
|
| 145 |
+
"lines": [
|
| 146 |
+
{
|
| 147 |
+
"file": "audio/v18.mp3",
|
| 148 |
+
"text": "每年十二月中旬,双子座还会送来一份盛大的礼物——双子座流星雨。",
|
| 149 |
+
"start": 127.29,
|
| 150 |
+
"end": 134.15
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"file": "audio/v19.mp3",
|
| 154 |
+
"text": "在理想的暗夜里,高峰时每小时能看到一百多颗流星。",
|
| 155 |
+
"start": 134.53,
|
| 156 |
+
"end": 140.12
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"file": "audio/v20.mp3",
|
| 160 |
+
"text": "大多数流星雨来自彗星,而它的母体,却是一颗名叫法厄同的小行星。",
|
| 161 |
+
"start": 140.5,
|
| 162 |
+
"end": 147.58
|
| 163 |
+
}
|
| 164 |
+
],
|
| 165 |
+
"end": 148.44
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"id": "discover",
|
| 169 |
+
"start": 148.44,
|
| 170 |
+
"lines": [
|
| 171 |
+
{
|
| 172 |
+
"file": "audio/v21.mp3",
|
| 173 |
+
"text": "双子座还见证过天文史上的重要时刻。",
|
| 174 |
+
"start": 149.16,
|
| 175 |
+
"end": 153.24
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"file": "audio/v22.mp3",
|
| 179 |
+
"text": "一七八一年,赫歇尔在双子座附近发现了天王星;",
|
| 180 |
+
"start": 153.62,
|
| 181 |
+
"end": 158.92
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"file": "audio/v23.mp3",
|
| 185 |
+
"text": "一九三零年,汤博在双子座天区的照片里,找到了冥王星。",
|
| 186 |
+
"start": 159.3,
|
| 187 |
+
"end": 165.35
|
| 188 |
+
}
|
| 189 |
+
],
|
| 190 |
+
"end": 166.21
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"id": "zodiac",
|
| 194 |
+
"start": 166.21,
|
| 195 |
+
"lines": [
|
| 196 |
+
{
|
| 197 |
+
"file": "audio/v24.mp3",
|
| 198 |
+
"text": "双子座也是黄道星座之一。每年六月下旬到七月下旬,太阳会从它的天区穿过。",
|
| 199 |
+
"start": 166.93,
|
| 200 |
+
"end": 175.57
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"file": "audio/v25.mp3",
|
| 204 |
+
"text": "而在占星文化里,五月二十一日到六月二十一日出生的人被称作双子座,",
|
| 205 |
+
"start": 175.95,
|
| 206 |
+
"end": 183.27
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"file": "audio/v26.mp3",
|
| 210 |
+
"text": "人们常用好奇、健谈、灵动来形容他们——当然,这只是一种有趣的文化想象。",
|
| 211 |
+
"start": 183.65,
|
| 212 |
+
"end": 191.33
|
| 213 |
+
}
|
| 214 |
+
],
|
| 215 |
+
"end": 192.19
|
| 216 |
+
},
|
| 217 |
+
{
|
| 218 |
+
"id": "outro",
|
| 219 |
+
"start": 192.19,
|
| 220 |
+
"lines": [
|
| 221 |
+
{
|
| 222 |
+
"file": "audio/v27.mp3",
|
| 223 |
+
"text": "两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 224 |
+
"start": 192.91,
|
| 225 |
+
"end": 199.63
|
| 226 |
+
},
|
| 227 |
+
{
|
| 228 |
+
"file": "audio/v28.mp3",
|
| 229 |
+
"text": "下一个晴朗的冬夜,记得抬头,找一找那对并肩的星星。",
|
| 230 |
+
"start": 200.01,
|
| 231 |
+
"end": 205.51
|
| 232 |
+
},
|
| 233 |
+
{
|
| 234 |
+
"file": "audio/v29.mp3",
|
| 235 |
+
"text": "它们已经在那里,等了你很久很久。",
|
| 236 |
+
"start": 205.89,
|
| 237 |
+
"end": 209.44
|
| 238 |
+
}
|
| 239 |
+
],
|
| 240 |
+
"end": 214.32
|
| 241 |
+
}
|
| 242 |
+
]
|
| 243 |
+
};
|
gemini-stars/tools/make_voice.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""生成双子座旁白音频与时间轴 timeline.js
|
| 2 |
+
依赖: pip install edge-tts imageio-ffmpeg
|
| 3 |
+
用法: python tools/make_voice.py
|
| 4 |
+
"""
|
| 5 |
+
import asyncio, json, os, re, subprocess
|
| 6 |
+
import edge_tts, imageio_ffmpeg
|
| 7 |
+
|
| 8 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
ROOT = os.path.dirname(HERE)
|
| 10 |
+
VOICE = "zh-CN-XiaoxiaoNeural"
|
| 11 |
+
RATE = "-4%"
|
| 12 |
+
|
| 13 |
+
SCENES = [
|
| 14 |
+
("intro", 2.6, [
|
| 15 |
+
"冬天的夜里,如果你抬头望向东方,会看到两颗明亮的星星,肩并着肩。",
|
| 16 |
+
"它们就像一对形影不离的兄弟——这,就是双子座。"]),
|
| 17 |
+
("find", 1.0, [
|
| 18 |
+
"想找到它很简单。先找到猎户座腰带上的三颗星,",
|
| 19 |
+
"再顺着猎户座的身体,向东北方向望过去。",
|
| 20 |
+
"那两颗挨得很近的亮星,就是双子的头:北河二和北河三。",
|
| 21 |
+
"从它们向下延伸出两串星,像两个手拉着手的小人,站在银河岸边。"]),
|
| 22 |
+
("myth", 1.2, [
|
| 23 |
+
"在古希腊神话里,他们是一对孪生兄弟:哥哥卡斯托尔擅长驯马,弟弟波吕克斯是拳击高手。",
|
| 24 |
+
"可他们的命运并不相同:卡斯托尔是凡人,而波吕克斯是宙斯之子,拥有不朽的生命。",
|
| 25 |
+
"一次争斗中,卡斯托尔中箭身亡。",
|
| 26 |
+
"波吕克斯悲痛万分,他请求宙斯:把我的不朽,分一半给哥哥吧。",
|
| 27 |
+
"宙斯被打动了。从此兄弟俩一天在天上,一天在冥界,永远不再分开,并肩化作了夜空中的双子座。"]),
|
| 28 |
+
("castor", 1.2, [
|
| 29 |
+
"神话很浪漫,而科学更惊奇。",
|
| 30 |
+
"哥哥北河二,用肉眼看只是一颗星,可在望远镜里,它分成了好几颗。",
|
| 31 |
+
"天文学家发现,它其实是六颗恒星组成的大家庭:三对双星彼此绕转,距离我们大约五十一光年。"]),
|
| 32 |
+
("pollux", 1.0, [
|
| 33 |
+
"弟弟北河三,是一颗橙色的巨星,距离我们大约三十四光年。",
|
| 34 |
+
"有趣的是,它排名叫“三”,却比“二”号哥哥更亮,是整个双子座最亮的星。",
|
| 35 |
+
"在它身旁,还有一颗质量至少是木星两倍的行星,默默绕转。"]),
|
| 36 |
+
("meteor", 1.2, [
|
| 37 |
+
"每年十二月中旬,双子座还会送来一份盛大的礼物——双子座流星雨。",
|
| 38 |
+
"在理想的暗夜里,高峰时每小时能看到一百多颗流星。",
|
| 39 |
+
"大多数流星雨来自彗星,而它的母体,却是一颗名叫法厄同的小行星。"]),
|
| 40 |
+
("discover", 1.2, [
|
| 41 |
+
"双子座还见证过天文史上的重要时刻。",
|
| 42 |
+
"一七八一年,赫歇尔在双子座附近发现了天王星;",
|
| 43 |
+
"一九三零年,汤博在双子座天区的照片里,找到了冥王星。"]),
|
| 44 |
+
("zodiac", 1.2, [
|
| 45 |
+
"双子座也是黄道星座之一。每年六月下旬到七月下旬,太阳会从它的天区穿过。",
|
| 46 |
+
"而在占星文化里,五月二十一日到六月二十一日出生的人被称作双子座,",
|
| 47 |
+
"人们常用好奇、健谈、灵动来形容他们——当然,这只是一种有趣的文化想象。"]),
|
| 48 |
+
("outro", 1.2, [
|
| 49 |
+
"两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 50 |
+
"下一个晴朗的冬夜,记得抬头,找一找那对并肩的星星。",
|
| 51 |
+
"它们已经在那里,等了你很久很久。"]),
|
| 52 |
+
]
|
| 53 |
+
GAP = 0.38
|
| 54 |
+
TAIL = 4.5
|
| 55 |
+
FF = imageio_ffmpeg.get_ffmpeg_exe()
|
| 56 |
+
|
| 57 |
+
def dur(path):
|
| 58 |
+
r = subprocess.run([FF, "-i", path], capture_output=True, text=True).stderr
|
| 59 |
+
h, m, s = re.search(r"Duration: (\d+):(\d+):([\d.]+)", r).groups()
|
| 60 |
+
return int(h) * 3600 + int(m) * 60 + float(s)
|
| 61 |
+
|
| 62 |
+
async def main():
|
| 63 |
+
os.makedirs(os.path.join(ROOT, "audio"), exist_ok=True)
|
| 64 |
+
t = 0.0; idx = 0; scenes = []
|
| 65 |
+
for sid, lead, lines in SCENES:
|
| 66 |
+
t += lead
|
| 67 |
+
sc = {"id": sid, "start": round(t - lead * 0.6 if scenes else 0, 3), "lines": []}
|
| 68 |
+
for text in lines:
|
| 69 |
+
idx += 1
|
| 70 |
+
fn = f"audio/v{idx:02d}.mp3"
|
| 71 |
+
out = os.path.join(ROOT, fn)
|
| 72 |
+
if not os.path.exists(out):
|
| 73 |
+
await edge_tts.Communicate(text, VOICE, rate=RATE).save(out)
|
| 74 |
+
d = dur(out)
|
| 75 |
+
sc["lines"].append({"file": fn, "text": text, "start": round(t, 3), "end": round(t + d, 3)})
|
| 76 |
+
t += d + GAP
|
| 77 |
+
scenes.append(sc)
|
| 78 |
+
for i, sc in enumerate(scenes):
|
| 79 |
+
sc["end"] = scenes[i + 1]["start"] if i + 1 < len(scenes) else round(t + TAIL, 3)
|
| 80 |
+
total = scenes[-1]["end"]
|
| 81 |
+
js = "// 由 tools/make_voice.py 自动生成,请勿手改\nexport const TIMELINE = " + json.dumps({"duration": total, "scenes": scenes}, ensure_ascii=False, indent=1) + ";\n"
|
| 82 |
+
open(os.path.join(ROOT, "timeline.js"), "w").write(js)
|
| 83 |
+
print("total", total)
|
| 84 |
+
|
| 85 |
+
asyncio.run(main())
|