kiku-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -0
- package/package.json +85 -0
- package/server/agent/agentCore.js +782 -0
- package/server/agent/agentState.js +140 -0
- package/server/agent/audioPlayer.js +673 -0
- package/server/agent/cli.js +1111 -0
- package/server/agent/commandRegistry.js +58 -0
- package/server/agent/commands.js +788 -0
- package/server/agent/config.js +90 -0
- package/server/agent/errors.js +9 -0
- package/server/agent/eventBus.js +103 -0
- package/server/agent/llmClient.js +200 -0
- package/server/agent/memory.js +566 -0
- package/server/agent/sanitizer.js +314 -0
- package/server/agent/session.js +239 -0
- package/server/agent/theme.js +124 -0
- package/server/agent/tools.js +1528 -0
- package/server/agent/ui.js +469 -0
- package/server/agent/webSearch.js +719 -0
- package/server/agent/youtubeAuth.js +299 -0
- package/server/mcp/claude-desktop-config.example.json +9 -0
- package/server/mcp/data/awards.js +14 -0
- package/server/mcp/data/brands.js +9 -0
- package/server/mcp/data/discography.js +36 -0
- package/server/mcp/data/gallery.js +25 -0
- package/server/mcp/data/index.js +7 -0
- package/server/mcp/data/profile.js +44 -0
- package/server/mcp/data/timeline.js +16 -0
- package/server/mcp/data/works.js +104 -0
- package/server/mcp/handler.js +159 -0
- package/server/mcp/prompts.js +143 -0
- package/server/mcp/resources.js +54 -0
- package/server/mcp/security.js +138 -0
- package/server/mcp/server.js +100 -0
- package/server/mcp/stdio.js +33 -0
- package/server/mcp/tools.js +126 -0
- package/src/data/awardsData.js +146 -0
- package/src/data/brandsData.js +249 -0
- package/src/data/discographyData.js +874 -0
- package/src/data/galleryData.js +666 -0
- package/src/data/musicVideoData.js +406 -0
- package/src/data/profileData.js +156 -0
- package/src/data/socialUpdatesData.js +381 -0
- package/src/data/timelineData.js +172 -0
- package/src/data/worksData.js +516 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { spawn, execSync } from 'child_process';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const ENV_PATH = path.resolve(__dirname, '..', '..', '.env');
|
|
8
|
+
const YTDLP_CMD = process.env.KIKU_YTDLP || 'yt-dlp';
|
|
9
|
+
|
|
10
|
+
const BROWSERS = ['chrome', 'edge', 'brave', 'firefox'];
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
function findBrowserExe(browser) {
|
|
15
|
+
const isWin = process.platform === 'win32';
|
|
16
|
+
const probes = {
|
|
17
|
+
chrome: { cmd: isWin ? 'chrome' : 'google-chrome', paths: [
|
|
18
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
19
|
+
(process.env.LOCALAPPDATA || '') + '\\Google\\Chrome\\Application\\chrome.exe',
|
|
20
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
|
|
21
|
+
]},
|
|
22
|
+
edge: { cmd: isWin ? 'msedge' : 'microsoft-edge', paths: [
|
|
23
|
+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
24
|
+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe'
|
|
25
|
+
]},
|
|
26
|
+
brave: { cmd: isWin ? 'brave' : 'brave-browser', paths: [
|
|
27
|
+
'C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe',
|
|
28
|
+
(process.env.LOCALAPPDATA || '') + '\\BraveSoftware\\Brave-Browser\\Application\\brave.exe'
|
|
29
|
+
]},
|
|
30
|
+
firefox: { cmd: isWin ? 'firefox' : 'firefox', paths: [
|
|
31
|
+
'C:\\Program Files\\Mozilla Firefox\\firefox.exe',
|
|
32
|
+
(process.env.LOCALAPPDATA || '') + '\\Mozilla Firefox\\firefox.exe'
|
|
33
|
+
]}
|
|
34
|
+
};
|
|
35
|
+
const p = probes[browser];
|
|
36
|
+
if (!p) return null;
|
|
37
|
+
try { execSync(isWin ? `where ${p.cmd}` : `which ${p.cmd}`, { stdio: 'ignore', windowsHide: true }); return p.cmd; } catch {}
|
|
38
|
+
if (isWin) {
|
|
39
|
+
for (const fp of p.paths) { if (fs.existsSync(fp)) return fp; }
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function detectBrowsers() {
|
|
45
|
+
return BROWSERS.filter(b => findBrowserExe(b) !== null);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function openBrowser(url, browser) {
|
|
49
|
+
const exe = browser ? findBrowserExe(browser) : null;
|
|
50
|
+
const isWin = process.platform === 'win32';
|
|
51
|
+
try {
|
|
52
|
+
if (exe) {
|
|
53
|
+
spawn(exe, [url], { windowsHide: true, stdio: 'ignore' });
|
|
54
|
+
} else if (isWin) {
|
|
55
|
+
spawn('cmd', ['/c', 'start', '', url], { windowsHide: true, stdio: 'ignore' });
|
|
56
|
+
} else if (process.platform === 'darwin') {
|
|
57
|
+
spawn('open', [url], { stdio: 'ignore' });
|
|
58
|
+
} else {
|
|
59
|
+
spawn('xdg-open', [url], { stdio: 'ignore' });
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(` [WARNING] Failed to open browser: ${err.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
function loadEnv() {
|
|
69
|
+
try {
|
|
70
|
+
if (!fs.existsSync(ENV_PATH)) return;
|
|
71
|
+
const text = fs.readFileSync(ENV_PATH, 'utf8');
|
|
72
|
+
for (const line of text.split('\n')) {
|
|
73
|
+
const m = line.match(/^\s*([\w.-]+)\s*=\s*(.*)\s*$/);
|
|
74
|
+
if (!m) continue;
|
|
75
|
+
const key = m[1];
|
|
76
|
+
let val = m[2].replace(/^["']|["']$/g, '');
|
|
77
|
+
if (process.env[key] === undefined) process.env[key] = val;
|
|
78
|
+
}
|
|
79
|
+
} catch {}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readEnvMap() {
|
|
83
|
+
const map = {};
|
|
84
|
+
try {
|
|
85
|
+
if (!fs.existsSync(ENV_PATH)) return map;
|
|
86
|
+
const text = fs.readFileSync(ENV_PATH, 'utf8');
|
|
87
|
+
for (const line of text.split('\n')) {
|
|
88
|
+
const m = line.match(/^\s*([\w.-]+)\s*=\s*(.*)\s*$/);
|
|
89
|
+
if (m) map[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
90
|
+
}
|
|
91
|
+
} catch {}
|
|
92
|
+
return map;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
function writeEnv(updates) {
|
|
97
|
+
const map = readEnvMap();
|
|
98
|
+
Object.assign(map, updates);
|
|
99
|
+
const out = Object.entries(map).map(([k, v]) => `${k}=${v}`).join('\n') + '\n';
|
|
100
|
+
fs.writeFileSync(ENV_PATH, out, 'utf8');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
function hasSession(browser) {
|
|
105
|
+
return new Promise((resolve) => {
|
|
106
|
+
const timeoutMs = 12000;
|
|
107
|
+
const args = [
|
|
108
|
+
'--cookies-from-browser', browser,
|
|
109
|
+
'--print', '%(title)s',
|
|
110
|
+
'--no-warnings',
|
|
111
|
+
'--no-check-certificates',
|
|
112
|
+
'ytsearch1:Ju Jingyi'
|
|
113
|
+
];
|
|
114
|
+
const p = spawn(YTDLP_CMD, args, {
|
|
115
|
+
windowsHide: true,
|
|
116
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
let out = '';
|
|
120
|
+
let err = '';
|
|
121
|
+
let resolved = false;
|
|
122
|
+
|
|
123
|
+
const timer = setTimeout(() => {
|
|
124
|
+
if (!resolved) {
|
|
125
|
+
resolved = true;
|
|
126
|
+
try { p.kill('SIGKILL'); } catch {}
|
|
127
|
+
resolve(false);
|
|
128
|
+
}
|
|
129
|
+
}, timeoutMs);
|
|
130
|
+
|
|
131
|
+
p.stdout.on('data', d => { out += d.toString(); });
|
|
132
|
+
p.stderr.on('data', d => { err += d.toString(); });
|
|
133
|
+
p.on('error', () => { if (!resolved) { resolved = true; clearTimeout(timer); resolve(false); } });
|
|
134
|
+
p.on('close', (code) => {
|
|
135
|
+
if (resolved) return;
|
|
136
|
+
resolved = true;
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
const title = out.trim();
|
|
139
|
+
const blocked = /403|Forbidden|Sign in|confirm you'?re not a bot|Login Required|Private Video/i.test(err);
|
|
140
|
+
resolve(code === 0 && title.length > 0 && !blocked);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
let _ensured = null;
|
|
148
|
+
let _lastFailTime = 0;
|
|
149
|
+
const RETRY_COOLDOWN_MS = 30000;
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
export async function ensureYouTubeCookies(opts = {}) {
|
|
153
|
+
|
|
154
|
+
if (_ensured && _ensured.ok) return _ensured;
|
|
155
|
+
if (_ensured && !_ensured.ok && (Date.now() - _lastFailTime) < RETRY_COOLDOWN_MS && !opts.force) {
|
|
156
|
+
return _ensured;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
loadEnv();
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if (process.env.KIKU_YT_COOKIES && fs.existsSync(process.env.KIKU_YT_COOKIES)) {
|
|
163
|
+
_ensured = { ok: true, source: 'file', cookiesPath: process.env.KIKU_YT_COOKIES };
|
|
164
|
+
return _ensured;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
const available = detectBrowsers();
|
|
169
|
+
if (!available.length) {
|
|
170
|
+
_ensured = { ok: false, reason: 'no-browser', detail: 'No supported browser found (Chrome, Edge, Brave, Firefox)' };
|
|
171
|
+
_lastFailTime = Date.now();
|
|
172
|
+
return _ensured;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
const preferred = process.env.KIKU_YT_BROWSER;
|
|
177
|
+
const candidates = preferred && available.includes(preferred)
|
|
178
|
+
? [preferred, ...available.filter(b => b !== preferred)]
|
|
179
|
+
: available;
|
|
180
|
+
|
|
181
|
+
for (const b of candidates) {
|
|
182
|
+
if (await hasSession(b)) {
|
|
183
|
+
|
|
184
|
+
writeEnv({ KIKU_YT_BROWSER: b });
|
|
185
|
+
process.env.KIKU_YT_BROWSER = b;
|
|
186
|
+
_ensured = { ok: true, source: 'existing-session', browser: b };
|
|
187
|
+
return _ensured;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if (opts.silent) {
|
|
193
|
+
_ensured = { ok: false, reason: 'no-session', available: candidates };
|
|
194
|
+
_lastFailTime = Date.now();
|
|
195
|
+
return _ensured;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
const loginBrowser = candidates[0];
|
|
200
|
+
const loginUrl = 'https://accounts.google.com/ServiceLogin?service=youtube&continue=https://www.youtube.com/';
|
|
201
|
+
openBrowser(loginUrl, loginBrowser);
|
|
202
|
+
|
|
203
|
+
console.log(`\n YouTube Login Required`);
|
|
204
|
+
console.log(` A browser (${loginBrowser}) has been opened for you to sign in to YouTube.`);
|
|
205
|
+
console.log(` Please complete the login, then come back here.`);
|
|
206
|
+
console.log(` Waiting for session... (timeout: ${Math.round((opts.timeout || 120000) / 1000)}s)\n`);
|
|
207
|
+
|
|
208
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
209
|
+
|
|
210
|
+
const deadline = Date.now() + (opts.timeout || 120000);
|
|
211
|
+
const pollInterval = 3000;
|
|
212
|
+
let attempt = 0;
|
|
213
|
+
|
|
214
|
+
while (Date.now() < deadline) {
|
|
215
|
+
attempt++;
|
|
216
|
+
const remaining = Math.round((deadline - Date.now()) / 1000);
|
|
217
|
+
process.stdout.write(`\r Checking... (attempt ${attempt}, ${remaining}s remaining) `);
|
|
218
|
+
|
|
219
|
+
for (const b of available) {
|
|
220
|
+
if (await hasSession(b)) {
|
|
221
|
+
writeEnv({ KIKU_YT_BROWSER: b });
|
|
222
|
+
process.env.KIKU_YT_BROWSER = b;
|
|
223
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
224
|
+
console.log(` [OK] YouTube session detected in ${b}.`);
|
|
225
|
+
console.log(` Saved KIKU_YT_BROWSER=${b} to .env\n`);
|
|
226
|
+
_ensured = { ok: true, source: 'new-session', browser: b };
|
|
227
|
+
return _ensured;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
await new Promise(r => setTimeout(r, pollInterval));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
235
|
+
console.log(` [ERROR] Login timed out. You can retry by running the /login command.\n`);
|
|
236
|
+
_ensured = { ok: false, reason: 'login-timeout' };
|
|
237
|
+
_lastFailTime = Date.now();
|
|
238
|
+
return _ensured;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
export async function exportCookiesToFile() {
|
|
243
|
+
loadEnv();
|
|
244
|
+
|
|
245
|
+
const available = detectBrowsers();
|
|
246
|
+
const preferred = process.env.KIKU_YT_BROWSER;
|
|
247
|
+
const candidates = preferred && available.includes(preferred)
|
|
248
|
+
? [preferred, ...available.filter(b => b !== preferred)]
|
|
249
|
+
: available;
|
|
250
|
+
|
|
251
|
+
for (const b of candidates) {
|
|
252
|
+
const cookiesPath = path.resolve(__dirname, '..', '..', '.kiku_yt_cookies.txt');
|
|
253
|
+
try {
|
|
254
|
+
const args = [
|
|
255
|
+
'--cookies-from-browser', b,
|
|
256
|
+
'--cookies', cookiesPath,
|
|
257
|
+
'--no-warnings',
|
|
258
|
+
'--skip-download',
|
|
259
|
+
'ytsearch1:__export_test__'
|
|
260
|
+
];
|
|
261
|
+
await new Promise((resolve, reject) => {
|
|
262
|
+
const p = spawn(YTDLP_CMD, args, { windowsHide: true, stdio: ['ignore', 'ignore', 'pipe'] });
|
|
263
|
+
let err = '';
|
|
264
|
+
p.stderr.on('data', d => { err += d.toString(); });
|
|
265
|
+
p.on('error', reject);
|
|
266
|
+
p.on('close', code => {
|
|
267
|
+
if (code === 0 && fs.existsSync(cookiesPath)) {
|
|
268
|
+
resolve();
|
|
269
|
+
} else {
|
|
270
|
+
reject(new Error(err || `yt-dlp exited ${code}`));
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
writeEnv({ KIKU_YT_COOKIES: cookiesPath });
|
|
276
|
+
process.env.KIKU_YT_COOKIES = cookiesPath;
|
|
277
|
+
return { ok: true, browser: b, cookiesPath };
|
|
278
|
+
} catch {}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { ok: false, reason: 'export-failed' };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function resetCookieCheck() {
|
|
285
|
+
_ensured = null;
|
|
286
|
+
_lastFailTime = 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function getCookieStatus() {
|
|
290
|
+
return {
|
|
291
|
+
ensured: _ensured,
|
|
292
|
+
envBrowser: process.env.KIKU_YT_BROWSER || null,
|
|
293
|
+
envCookies: process.env.KIKU_YT_COOKIES || null,
|
|
294
|
+
envPath: ENV_PATH
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
loadEnv();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const awardsData = [
|
|
2
|
+
{ id: "aw-2024-weibo", year: 2024, title: "Popular Actress of the Year", titleCn: "年度人气女演员", ceremony: "Weibo TV & Internet Video Summit 2024", work: "In Blossom", category: "Acting" },
|
|
3
|
+
{ id: "aw-2023-weibo-night", year: 2023, title: "Influential Figure of the Year", titleCn: "年度影响力艺人", ceremony: "Weibo Night 2023", work: "Beauty of Resilience", category: "Honor" },
|
|
4
|
+
{ id: "aw-2022-erc", year: 2022, title: "Popular Singer of the Year", titleCn: "年度最佳人气歌手", ceremony: "29th ERC Chinese Top Ten Awards", work: "Single '0.2s'", category: "Music" },
|
|
5
|
+
{ id: "aw-2021-tencent", year: 2021, title: "Outstanding Actress of the Year", titleCn: "年度卓越女演员", ceremony: "Tencent Video Starlight Awards 2021", work: "Rebirth for You", category: "Acting" },
|
|
6
|
+
{ id: "aw-2020-erc", year: 2020, title: "Best Stage Performance", titleCn: "最佳舞台表演", ceremony: "27th ERC Chinese Top Ten Awards", work: "Live Stage Performances", category: "Music" },
|
|
7
|
+
{ id: "aw-2020-iqiyi", year: 2020, title: "Breakthrough Actress of the Year", titleCn: "年度突破女演员", ceremony: "iQIYI Scream Night 2020", work: "In a Class of Her Own", category: "Acting" },
|
|
8
|
+
{ id: "aw-2019-qq", year: 2019, title: "Drama Actress of the Year", titleCn: "年度电视剧女演员", ceremony: "iQIYI Scream Night 2019", work: "The Legend of White Snake", category: "Acting" },
|
|
9
|
+
{ id: "aw-2018-weibo", year: 2018, title: "Breakthrough Actress of the Year", titleCn: "年度突破女演员", ceremony: "Weibo TV & Internet Video Summit 2018", work: "Legend of Yunxi", category: "Acting" },
|
|
10
|
+
{ id: "aw-2017-snh48", year: 2017, title: "SNH48 General Election Champion (2nd consecutive)", titleCn: "SNH48总选举冠军(蝉联)", ceremony: "SNH48 4th General Election", work: "SNH48", category: "Honor" },
|
|
11
|
+
{ id: "aw-2016-snh48", year: 2016, title: "SNH48 General Election Champion", titleCn: "SNH48总选举冠军", ceremony: "SNH48 3rd General Election", work: "SNH48", category: "Honor" },
|
|
12
|
+
{ id: "aw-2015-snh48", year: 2015, title: "SNH48 General Election Runner-up", titleCn: "SNH48总选举亚军", ceremony: "SNH48 2nd General Election", work: "SNH48", category: "Honor" },
|
|
13
|
+
{ id: "aw-2014-snh48", year: 2014, title: "SNH48 General Election 4th Place", titleCn: "SNH48总选举第4名", ceremony: "SNH48 1st General Election", work: "SNH48", category: "Honor" },
|
|
14
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const brandsData = [
|
|
2
|
+
{ id: "prsr", year: 2026, brandNameEn: "PRSR / Pasha", brandNameCn: "帕莎眼镜", title: "Global Brand Ambassador", category: "Luxury Eyewear", isGlobal: true, highlight: "Milan Fashion Week 2026 debut, viral pink sequin look" },
|
|
3
|
+
{ id: "fred", year: 2026, brandNameEn: "FRED Jewelry", brandNameCn: "FRED珠宝", title: "Brand Ambassador", category: "Luxury Jewelry", isGlobal: false, highlight: "Force 10 High Jewelry editorial for PORT Magazine" },
|
|
4
|
+
{ id: "tutucare", year: 2025, brandNameEn: "TuTuCare", brandNameCn: "凸凸棉", title: "Brand Ambassador", category: "Baby Care", isGlobal: false, highlight: "20,000 gift boxes sold out in 1 second, GMV 10.3M CNY in 1 hour" },
|
|
5
|
+
{ id: "dafuyan", year: 2025, brandNameEn: "DAFUYAN", brandNameCn: "达肤妍", title: "Brand Ambassador", category: "Skincare", isGlobal: false, highlight: "10,000 sets sold out in 8 minutes, 20M CNY in 24 hours" },
|
|
6
|
+
{ id: "lafang", year: 2025, brandNameEn: "Lafang", brandNameCn: "拉芳", title: "Global Brand Ambassador", category: "Hair Care", isGlobal: true, highlight: "First Global Ambassador in brand's 30-year history" },
|
|
7
|
+
{ id: "oppo", year: 2024, brandNameEn: "OPPO", brandNameCn: "OPPO", title: "Brand Ambassador", category: "Technology", isGlobal: false, highlight: "Smartphone campaign across Asia" },
|
|
8
|
+
{ id: "loreal", year: 2024, brandNameEn: "L'Oréal Paris", brandNameCn: "巴黎欧莱雅", title: "Brand Ambassador", category: "Beauty", isGlobal: true, highlight: "Global beauty ambassador for L'Oréal Paris" },
|
|
9
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const discographyData = [
|
|
2
|
+
{ id: "find-the-way", titleEn: "FIND THE WAY", titleCn: "FIND THE WAY", year: 2026, category: "single", duration: "3:30", youtubeId: "9AeErG03SZw" },
|
|
3
|
+
{ id: "set-fire", titleEn: "Set Fire to the Silent World", titleCn: "着火的沉默世界", year: 2026, category: "ost", duration: "3:55", youtubeId: "7FXGhAmHIAo", work: "Wanhua Sin" },
|
|
4
|
+
{ id: "not-suffering", titleEn: "Not Suffering", titleCn: "不苦", year: 2026, category: "ost", duration: "3:50", youtubeId: "DafSXZZo9AI", work: "Veil of Shadows" },
|
|
5
|
+
{ id: "eternal-fragrance-song", titleEn: "The Eternal Fragrance", titleCn: "千香", year: 2026, category: "ost", duration: "3:46", youtubeId: "vIanAvWb_HU", work: "The Eternal Fragrance" },
|
|
6
|
+
{ id: "rain-love", titleEn: "Yu Ai (Rain Love)", titleCn: "雨爱", year: 2026, category: "cover", duration: "4:10", youtubeId: "OMLpNyp8T7Q" },
|
|
7
|
+
{ id: "rosa", titleEn: "Rosa", titleCn: "Rosa", year: 2025, category: "single", duration: "3:20", youtubeId: "jZDzOLbd9OU" },
|
|
8
|
+
{ id: "sleepless-sunset", titleEn: "Sleepless Sunset", titleCn: "落日未眠", year: 2025, category: "single", duration: "3:45", youtubeId: "mYYD2JqZ1tE" },
|
|
9
|
+
{ id: "fall", titleEn: "Fall", titleCn: "落", year: 2024, category: "single", duration: "3:36", youtubeId: "8Nh4ZPhYKEc" },
|
|
10
|
+
{ id: "view-from-wall", titleEn: "View From The Wall", titleCn: "壁上观", year: 2024, category: "single", duration: "3:50", youtubeId: "Lge5XhVl9Fc" },
|
|
11
|
+
{ id: "ru-sha", titleEn: "Ru Sha", titleCn: "如纱", year: 2024, category: "ost", duration: "3:42", youtubeId: "lzDP2MfP3eA", work: "Sword and Fairy 4" },
|
|
12
|
+
{ id: "in-blossom-ost", titleEn: "In Blossom Main Theme", titleCn: "花间令", year: 2024, category: "ost", youtubeId: null, work: "In Blossom" },
|
|
13
|
+
{ id: "thoughts-of-joy", titleEn: "Thoughts of Joy", titleCn: "念思凡", year: 2023, category: "ost", duration: "4:05", youtubeId: "D-vEPdasbLo", work: "Beauty of Resilience" },
|
|
14
|
+
{ id: "dew-before-dawn", titleEn: "Dew Before Dawn", titleCn: "露珠在晨曦前消散", year: 2023, category: "ost", youtubeId: null, work: "Beauty of Resilience" },
|
|
15
|
+
{ id: "0.2s", titleEn: "0.2s", titleCn: "0.2s", year: 2022, category: "single", duration: "3:20", youtubeId: null },
|
|
16
|
+
{ id: "mo-li", titleEn: "Mo Li", titleCn: "莫离", year: 2021, category: "ost", duration: "4:12", youtubeId: "7VSAArsR-go", work: "Rebirth for You" },
|
|
17
|
+
{ id: "qing-cheng-shan-xia", titleEn: "Qing Cheng Shan Xia", titleCn: "青城山下", year: 2021, category: "single", youtubeId: null },
|
|
18
|
+
{ id: "fu-rong", titleEn: "Fu Rong", titleCn: "芙蓉", year: 2020, category: "ost", duration: "3:58", youtubeId: "9ke3efb9U7A", work: "The Blooms at Ruyi Pavilion" },
|
|
19
|
+
{ id: "ancient-painting", titleEn: "Ancient Painting", titleCn: "古画", year: 2020, category: "ost", youtubeId: null, work: "The Blooms at Ruyi Pavilion" },
|
|
20
|
+
{ id: "thousand-years", titleEn: "A Millennium's Wait", titleCn: "千年等一回", year: 2019, category: "ost", duration: "3:44", youtubeId: "-vf6jU96WI4", work: "The Legend of White Snake" },
|
|
21
|
+
{ id: "du-qing", titleEn: "Du Qing", titleCn: "渡情", year: 2019, category: "ost", youtubeId: null, work: "The Legend of White Snake" },
|
|
22
|
+
{ id: "wudaoying", titleEn: "Wu Dao Ying", titleCn: "舞导演", year: 2019, category: "single", youtubeId: null },
|
|
23
|
+
{ id: "gufeng-shanshui", titleEn: "Gufeng Shanshui", titleCn: "古风山水", year: 2019, category: "single", youtubeId: null },
|
|
24
|
+
{ id: "meng-lu", titleEn: "Meng Lu (Dream Road)", titleCn: "梦路", year: 2018, category: "single", youtubeId: null },
|
|
25
|
+
{ id: "zui-chi-luo", titleEn: "Zui Chi Luo", titleCn: "最赤裸", year: 2018, category: "single", youtubeId: null },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export const musicVideos = [
|
|
29
|
+
{ id: "mv-find-the-way", titleEn: "FIND THE WAY MV", titleCn: "FIND THE WAY", year: 2026, category: "Official MV", youtubeId: "9AeErG03SZw", duration: "3:30" },
|
|
30
|
+
{ id: "mv-not-suffering", titleEn: "Not Suffering MV", titleCn: "不苦", year: 2026, category: "OST MV", youtubeId: "DafSXZZo9AI", duration: "3:50", work: "Veil of Shadows" },
|
|
31
|
+
{ id: "mv-rain-love", titleEn: "Yu Ai (Rain Love) Stage", titleCn: "雨爱", year: 2026, category: "Stage Performance", youtubeId: "OMLpNyp8T7Q", duration: "4:10" },
|
|
32
|
+
{ id: "mv-set-fire", titleEn: "Set Fire to the Silent World MV", titleCn: "着火的沉默世界", year: 2026, category: "OST MV", youtubeId: "7FXGhAmHIAo", duration: "3:55", work: "Wanhua Sin" },
|
|
33
|
+
{ id: "mv-rosa", titleEn: "Rosa MV", titleCn: "Rosa", year: 2025, category: "Official MV", youtubeId: "jZDzOLbd9OU", duration: "3:20" },
|
|
34
|
+
{ id: "mv-fall", titleEn: "Fall MV", titleCn: "落", year: 2024, category: "Official MV", youtubeId: "8Nh4ZPhYKEc", duration: "3:36" },
|
|
35
|
+
{ id: "mv-ru-sha", titleEn: "Ru Sha MV", titleCn: "如纱", year: 2024, category: "OST MV", youtubeId: "lzDP2MfP3eA", duration: "3:42", work: "Sword and Fairy 4" },
|
|
36
|
+
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const galleryData = [
|
|
2
|
+
{ id: "gal-port-2026", titleEn: "PORT Magazine September Cover", titleCn: "PORT中文版九月刊封面", category: "fashion-magazine", era: "2026", description: "Desert Haute Couture photoshoot for PORT Magazine Gold Issue. First woman to cover PORT Chinese edition. Wrote the fashion editorial herself." },
|
|
3
|
+
{ id: "gal-fred-jewelry", titleEn: "FRED Force 10 High Jewelry", titleCn: "FRED高级珠宝", category: "fashion-magazine", era: "2026", description: "Editorial shoot featuring FRED Force 10 High Jewelry collection during PORT desert shoot." },
|
|
4
|
+
{ id: "gal-prsr-milan", titleEn: "PRSR Milan Fashion Week", titleCn: "帕莎眼镜米兰时装周", category: "fashion-magazine", era: "2026", description: "Viral look at Milan Fashion Week for PRSR Global Brand Ambassador debut." },
|
|
5
|
+
{ id: "gal-veil-promo", titleEn: "Veil of Shadows Press Conference", titleCn: "月鳞绮纪发布会", category: "event", era: "2026", description: "Cast press conference for Veil of Shadows drama premiere on Youku." },
|
|
6
|
+
{ id: "gal-eternal-fragrance-promo", titleEn: "The Eternal Fragrance Promotional Event", titleCn: "千香宣传活动", category: "event", era: "2026", description: "Promotional event for The Eternal Fragrance with co-star Song Weilong." },
|
|
7
|
+
{ id: "gal-redcarpet-weibo-2025", titleEn: "Weibo Night 2025 Red Carpet", titleCn: "微博之夜红毯", category: "red-carpet", era: "2025", description: "Red carpet appearance at Weibo Night annual gala 2025." },
|
|
8
|
+
{ id: "gal-redcarpet-tencent-2021", titleEn: "Tencent Video Starlight Awards 2021", titleCn: "腾讯视频星光大赏", category: "red-carpet", era: "2021", description: "Red carpet at Tencent Video Starlight Awards where she won Outstanding Actress." },
|
|
9
|
+
{ id: "gal-in-blossom-stills", titleEn: "In Blossom Drama Stills", titleCn: "花间令剧照", category: "drama-stills", era: "2024", description: "Behind-the-scenes and promotional stills from In Blossom dual-role performance." },
|
|
10
|
+
{ id: "gal-sword-fairy-stills", titleEn: "Sword and Fairy 4 Stills", titleCn: "仙剑四剧照", category: "drama-stills", era: "2024", description: "Drama stills featuring iconic red Han Lingsha costume." },
|
|
11
|
+
{ id: "gal-beauty-stills", titleEn: "Beauty of Resilience Stills", titleCn: "花戎剧照", category: "drama-stills", era: "2023", description: "Promotional stills from Beauty of Resilience triple-role performance." },
|
|
12
|
+
{ id: "gal-white-snake-stills", titleEn: "Legend of White Snake Stills", titleCn: "新白娘子传奇剧照", category: "drama-stills", era: "2019", description: "Drama stills as Bai Suzhen in the classic White Snake remake." },
|
|
13
|
+
{ id: "gal-yunxi-stills", titleEn: "Legend of Yunxi Stills", titleCn: "芸汐传剧照", category: "drama-stills", era: "2018", description: "Breakthrough role stills as Han Yunxi." },
|
|
14
|
+
{ id: "gal-wallpaper-2026-1", titleEn: "2026 Desktop Wallpaper — Sakura", titleCn: "2026桌面壁纸·樱花", category: "wallpaper", era: "2026", description: "High-resolution desktop wallpaper with sakura theme." },
|
|
15
|
+
{ id: "gal-wallpaper-2026-2", titleEn: "2026 Desktop Wallpaper — Desert", titleCn: "2026桌面壁纸·沙漠", category: "wallpaper", era: "2026", description: "High-resolution desktop wallpaper from PORT desert shoot." },
|
|
16
|
+
{ id: "gal-wallpaper-2025", titleEn: "2025 Desktop Wallpaper — Rose", titleCn: "2025桌面壁纸·玫瑰", category: "wallpaper", era: "2025", description: "High-resolution desktop wallpaper with rose/garden theme." },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const galleryCategories = [
|
|
20
|
+
{ id: "fashion-magazine", label: "Fashion & Magazine", count: 3 },
|
|
21
|
+
{ id: "red-carpet", label: "Red Carpet", count: 2 },
|
|
22
|
+
{ id: "event", label: "Events", count: 2 },
|
|
23
|
+
{ id: "drama-stills", label: "Drama Stills", count: 5 },
|
|
24
|
+
{ id: "wallpaper", label: "Wallpapers", count: 3 },
|
|
25
|
+
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { profileData } from './profile.js';
|
|
2
|
+
export { worksData } from './works.js';
|
|
3
|
+
export { discographyData, musicVideos } from './discography.js';
|
|
4
|
+
export { galleryData, galleryCategories } from './gallery.js';
|
|
5
|
+
export { timelineData } from './timeline.js';
|
|
6
|
+
export { awardsData } from './awards.js';
|
|
7
|
+
export { brandsData } from './brands.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const profileData = {
|
|
2
|
+
nameTh: "จวีจิ้งอี",
|
|
3
|
+
nameEn: "Ju Jingyi",
|
|
4
|
+
nameCn: "鞠婧祎",
|
|
5
|
+
pinyin: "Jū Jìngyī",
|
|
6
|
+
nickname: "Kiku / เสี่ยวจวี (小鞠)",
|
|
7
|
+
titleBadge: "ไอดอลสาว 4,000 ปี (中国4000年一遇偶像)",
|
|
8
|
+
englishAliases: "Kiku Ju / Cecilia Ju",
|
|
9
|
+
motto: "保持热爱,奔赴山海",
|
|
10
|
+
mottoTranslation: "Maintain your passion and stride boldly toward the mountains and seas.",
|
|
11
|
+
bioSummary: "Ju Jingyi (鞠婧祎) is a Chinese singer, dancer, and actress. A former SNH48 2nd Generation member (Team NII, debuting 2013), she made history as a two-time General Election champion (2016–2017) and was inducted into the SNH48 Star Hall of Fame. She is now one of China's top independent solo artists and actresses.",
|
|
12
|
+
details: {
|
|
13
|
+
birthDate: "June 18, 1994",
|
|
14
|
+
birthPlace: "Suining, Sichuan, China",
|
|
15
|
+
height: "159 cm",
|
|
16
|
+
bloodType: "O",
|
|
17
|
+
zodiac: "Gemini",
|
|
18
|
+
education: "Sichuan Conservatory of Music (Attached Middle School) — Classical Violin",
|
|
19
|
+
debutDate: "November 2, 2013 (SNH48 2nd Gen Team NII)",
|
|
20
|
+
graduationDate: "December 15, 2017 (SNH48 Star Hall of Fame)",
|
|
21
|
+
currentStatus: "Solo Artist & Freelance Actress / Ju Jingyi Studio",
|
|
22
|
+
fandomName: "Miju (蜜橘)",
|
|
23
|
+
fandomColors: "Crystal Blue & Sakura Pink (#58B2DC & #FAD2E1)",
|
|
24
|
+
},
|
|
25
|
+
talents: [
|
|
26
|
+
{ id: "violin", title: "Classical Violin", level: "Advanced (Sichuan Conservatory training)" },
|
|
27
|
+
{ id: "guzheng", title: "Guzheng (古筝)", level: "Intermediate" },
|
|
28
|
+
{ id: "piano", title: "Piano", level: "Intermediate" },
|
|
29
|
+
{ id: "vocal", title: "Vocal / OST Singing", level: "Professional" },
|
|
30
|
+
{ id: "dance", title: "Traditional Chinese Dance", level: "Professional" },
|
|
31
|
+
],
|
|
32
|
+
quotes: [
|
|
33
|
+
{ textCn: "保持热爱,奔赴山海", textEn: "Maintain your passion and stride boldly toward the mountains and seas.", tag: "mindset" },
|
|
34
|
+
{ textCn: "努力是唯一不会背叛你的东西", textEn: "Hard work is the only thing that will never betray you.", tag: "growth" },
|
|
35
|
+
{ textCn: "我想成为那种,不管在什么环境下都能发光的人", textEn: "I want to be the kind of person who shines in any environment.", tag: "mindset" },
|
|
36
|
+
],
|
|
37
|
+
socialMedia: {
|
|
38
|
+
weibo: "https://weibo.com/jujingyi",
|
|
39
|
+
douyin: "https://www.douyin.com/user/jujingyi",
|
|
40
|
+
instagram: "https://www.instagram.com/jujingyi_official",
|
|
41
|
+
bilibili: "https://space.bilibili.com/jujingyi",
|
|
42
|
+
youtube: "https://www.youtube.com/@jujingyi",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const timelineData = [
|
|
2
|
+
{ id: "debut-2013", year: 2013, title: "SNH48 2nd Generation Debut (Team NII)", titleCn: "SNH48二期生出道", era: "SNH48 Era", summary: "Debuted as member of SNH48 2nd Generation Team NII, performing Theater Goddess (剧场女神) stage. Left school to pursue idol career." },
|
|
3
|
+
{ id: "fame-2014", year: 2014, title: "4th Place General Election & '4000-Year Idol'", titleCn: "总选举第4名·4000年偶像", era: "SNH48 Era", summary: "4th place in 1st General Election. Japanese media dubbed her 'idol who appears once in 4000 years' (中国4000年一遇偶像) — viral across Asia." },
|
|
4
|
+
{ id: "senbatsu-2015", year: 2015, title: "2nd Place General Election & Seine River Unit", titleCn: "总选举亚军·塞纳河组合", era: "SNH48 Era", summary: "Runner-up in 2nd General Election. Member of Seine River (塞纳河) performance unit." },
|
|
5
|
+
{ id: "election-2016", year: 2016, title: "1st General Election Champion", titleCn: "总选举冠军", era: "SNH48 Era", summary: "Won 1st place in SNH48 3rd General Election, becoming center. First of two consecutive championships." },
|
|
6
|
+
{ id: "election-2017", year: 2017, title: "2nd Consecutive Champion & Star Hall of Fame", titleCn: "蝉联冠军·星殿堂", era: "SNH48 Era", summary: "Won 1st place again (2nd consecutive). Inducted into SNH48 Star Hall of Fame. Graduated December 15, 2017." },
|
|
7
|
+
{ id: "fallen-flowers-2017", year: 2017, title: "The Fallen Flowers (热血长安)", titleCn: "热血长安", era: "Solo Career", summary: "First major acting role after SNH48 graduation. Historical mystery drama on Youku as Shangguan Wan'er." },
|
|
8
|
+
{ id: "yunxi-2018", year: 2018, title: "Acting Breakthrough — Legend of Yunxi", titleCn: "芸汐传·演技突破", era: "Solo Career", summary: "Lead role in Legend of Yunxi (芸汐传). Breakthrough as solo actress. Won Breakthrough Actress at Weibo TV & Video Summit." },
|
|
9
|
+
{ id: "white-snake-2019", year: 2019, title: "The Legend of White Snake & Please Give Me Wings", titleCn: "新白娘子传奇·请赐我一双翅膀", era: "Solo Career", summary: "Starred as Bai Suzhen in classic remake. Also appeared in modern crime thriller. Won Drama Actress of the Year." },
|
|
10
|
+
{ id: "ruyi-2020", year: 2020, title: "Ruyi Pavilion & In a Class of Her Own & Eagle Flag", titleCn: "如意芳霏·漂亮书生·天空城II", era: "Solo Career", summary: "Three dramas in one year: The Blooms at Ruyi Pavilion, In a Class of Her Own (male disguise), and Novoland: Eagle Flag. Breakthrough Actress at iQIYI Scream Night." },
|
|
11
|
+
{ id: "rebirth-2021", year: 2021, title: "Rebirth for You & Rising Stardom", titleCn: "嘉南传·星途上升", era: "Solo Career", summary: "Lead in Rebirth for You. Won Outstanding Actress at Tencent Video Starlight Awards. Established as top-tier actress and brand ambassador." },
|
|
12
|
+
{ id: "resilience-2023", year: 2023, title: "Beauty of Resilience & Influential Figure", titleCn: "花戎·影响力人物", era: "Solo Career", summary: "Xianxia drama Beauty of Resilience with triple-role performance. Won Influential Figure of the Year at Weibo Night." },
|
|
13
|
+
{ id: "blossom-2024", year: 2024, title: "In Blossom & Contract Resolution", titleCn: "花间令·合约纷争解决", era: "Solo Career", summary: "Lead in In Blossom (花间令) with acclaimed dual-role. Won Popular Actress of the Year. Resolved contract dispute with Star48/Siba Media. Confirmed independent status." },
|
|
14
|
+
{ id: "brand-2025", year: 2025, title: "Mega Brand Deals & International Expansion", titleCn: "国际品牌代言扩张", era: "Present", summary: "Global brand ambassador roles across luxury and fashion brands. International presence expansion. Solo singles Rosa and Sleepless Sunset released." },
|
|
15
|
+
{ id: "2026-present", year: 2026, title: "Veil of Shadows, Eternal Fragrance, Wanhua Sin & FIND THE WAY", titleCn: "月鳞绮纪·千香·万花世界·FIND THE WAY", era: "Present", summary: "Multiple major 2026 projects: Veil of Shadows (Youku #1), The Eternal Fragrance (Youku S+), Wanhua Sin, solo single FIND THE WAY, special stage Yu Ai (Rain Love). PRSR Global Brand Ambassador debut at Milan Fashion Week." },
|
|
16
|
+
];
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export const worksData = [
|
|
2
|
+
{
|
|
3
|
+
id: "veil-of-shadows", titleEn: "Veil of Shadows", titleCn: "月鳞绮纪", year: 2026,
|
|
4
|
+
category: "historical-drama", role: "Lu Wuyi (露芜衣) — Nine-tailed Fox",
|
|
5
|
+
roleCn: "露芜衣", episodes: 38, rating: "9.6/10", platform: "Youku",
|
|
6
|
+
synopsis: "Fantasy epic directed by Guo Jingming. Lu Wuyi, a nine-tailed fox from the Moon Scale Hall, goes undercover to investigate mysterious murders and battles the ancient Nine-Headed Demon (Jiuying).",
|
|
7
|
+
themeSong: { titleEn: "Not Suffering", titleCn: "不苦", youtubeId: "DafSXZZo9AI" },
|
|
8
|
+
featured: true, highlights: ["Fastest 10,000 popularity index on Youku (52 hours)", "2 billion+ views on Weibo and Douyin", "Destiny Theme '不苦' duet with Tian Jiarui topped Chinese charts"],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "eternal-fragrance", titleEn: "The Eternal Fragrance", titleCn: "千香", year: 2026,
|
|
12
|
+
category: "historical-drama", role: "Jiang Lifei / Xiao Bangchui (姜黎非 / 小棒槌)",
|
|
13
|
+
roleCn: "姜黎非 / 小棒槌", episodes: 33, rating: "9.3/10", platform: "Youku",
|
|
14
|
+
synopsis: "S+ fantasy drama adapted from novel 《千香百态》. Jiang Lifei enters Chufeng Academy to find her master, meeting Lei Xiuyuan (Song Weilong). They face destiny across three lifetimes.",
|
|
15
|
+
themeSong: { titleEn: "The Eternal Fragrance", titleCn: "千香", youtubeId: "vIanAvWb_HU" },
|
|
16
|
+
featured: true, highlights: ["Reunion of popular pairing Ju Jingyi + Song Weilong", "Top-tier VFX and costumes by Youku"],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "wanhua-sin", titleEn: "Wanhua Sin", titleCn: "万花世界", year: 2026,
|
|
20
|
+
category: "fantasy-drama", role: "Lead Role", platform: "TBA",
|
|
21
|
+
synopsis: "Upcoming fantasy epic. Promo OST: 'Set Fire to the Silent World' (着火的沉默世界).",
|
|
22
|
+
themeSong: { titleEn: "Set Fire to the Silent World", titleCn: "着火的沉默世界", youtubeId: "7FXGhAmHIAo" },
|
|
23
|
+
featured: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "in-blossom", titleEn: "In Blossom", titleCn: "花间令", year: 2024,
|
|
27
|
+
category: "historical-drama", role: "Yang Caiwei / Shangguan Zhi (杨采薇 / 上官芷)",
|
|
28
|
+
roleCn: "杨采薇 / 上官芷", episodes: 32, rating: "9.5/10", platform: "Youku",
|
|
29
|
+
synopsis: "Romantic mystery set in ancient China. Yang Caiwei, a woman presumed dead, returns in a new identity to solve mysteries alongside the man who loved her.",
|
|
30
|
+
featured: true, highlights: ["Popular Actress of the Year — Weibo TV & Video Summit 2024", "Fastest 10,000 popularity index on Youku in 2024", "Acclaimed dual-role performance with contrasting personalities"],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "sword-fairy-4", titleEn: "Sword and Fairy 4", titleCn: "仙剑四", year: 2024,
|
|
34
|
+
category: "xianxia-drama", role: "Han Lingsha (韩菱纱)",
|
|
35
|
+
roleCn: "韩菱纱", episodes: 36, rating: "8.9/10", platform: "iQIYI",
|
|
36
|
+
synopsis: "Adapted from the classic RPG. Han Lingsha, a spirited tomb raider, joins forces with Yun Tianhe on an adventure to save the world.",
|
|
37
|
+
themeSong: { titleEn: "Ru Sha", titleCn: "如纱", youtubeId: "lzDP2MfP3eA" },
|
|
38
|
+
highlights: ["Iconic red costume faithful to the game", "#1 trending on iQIYI across China and Southeast Asia"],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "beauty-of-resilience", titleEn: "Beauty of Resilience", titleCn: "花戎", year: 2023,
|
|
42
|
+
category: "xianxia-drama", role: "Wei Zhi / Sima Wangyue / A Ya (魏枝 / 司马忘月 / 阿涯)",
|
|
43
|
+
roleCn: "魏枝 / 司马忘月 / 阿涯", episodes: 36, rating: "8.9/10", platform: "iQIYI",
|
|
44
|
+
synopsis: "Xianxia romance. Wei Zhi, a servant girl deemed unlucky, is actually the reincarnation of the Phoenix. She meets Yan Yue, a sun god disguised as her master.",
|
|
45
|
+
themeSong: { titleEn: "Thoughts of Joy", titleCn: "念思凡", youtubeId: "D-vEPdasbLo" },
|
|
46
|
+
highlights: ["Triple-role performance across 3 lifetimes", "8,500+ popularity index on iQIYI in first week"],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "rebirth-for-you", titleEn: "Rebirth for You", titleCn: "嘉南传", year: 2021,
|
|
50
|
+
category: "historical-drama", role: "Jiang Baoning (姜保宁 / 嘉南郡主)",
|
|
51
|
+
roleCn: "姜保宁 / 嘉南郡主", episodes: 40, rating: "9.1/10", platform: "Tencent Video",
|
|
52
|
+
synopsis: "Adapted from novel 《慕南枝》. Princess Jiang Baoning, clever and independent, teams up with soldier Li Qian to navigate court politics.",
|
|
53
|
+
themeSong: { titleEn: "Mo Li", titleCn: "莫离", youtubeId: "7VSAArsR-go" },
|
|
54
|
+
highlights: ["Most Popular Actress — Tencent Video Starlight Awards 2021", "Viral bead headdress fashion trend"],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "ruyi-pavilion", titleEn: "The Blooms at Ruyi Pavilion", titleCn: "如意芳霏", year: 2020,
|
|
58
|
+
category: "historical-drama", role: "Fu Rong (傅容)",
|
|
59
|
+
roleCn: "傅容", episodes: 40, rating: "9.2/10", platform: "iQIYI",
|
|
60
|
+
synopsis: "Fu Rong, the second daughter of the Fu family, has prophetic dreams. She tries to escape her predicted fate of marrying Prince Su, but finds love instead.",
|
|
61
|
+
themeSong: { titleEn: "Fu Rong", titleCn: "芙蓉", youtubeId: "9ke3efb9U7A" },
|
|
62
|
+
highlights: ["Reunion of Legend of Yunxi pairing", "#1 on iQIYI in 10+ Asian countries"],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "in-a-class-of-her-own", titleEn: "In a Class of Her Own", titleCn: "漂亮书生", year: 2020,
|
|
66
|
+
category: "historical-drama", role: "Xue Wenxi / Wen Bin (雪文曦 / 文彬)",
|
|
67
|
+
roleCn: "雪文曦 / 文彬", episodes: 36, rating: "8.8/10", platform: "iQIYI",
|
|
68
|
+
synopsis: "Romantic comedy. Xue Wenxi disguises herself as a man to earn a living, accidentally entering an all-male academy where she forms the 'Four Scholars of Yunshang'.",
|
|
69
|
+
highlights: ["Breakthrough Actress — iQIYI Scream Night 2020", "Iconic male-disguise look went viral across Asia"],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "legend-of-white-snake", titleEn: "The Legend of White Snake", titleCn: "新白娘子传奇", year: 2019,
|
|
73
|
+
category: "fantasy-drama", role: "Bai Suzhen (白素贞)",
|
|
74
|
+
roleCn: "白素贞", episodes: 36, rating: "9.3/10", platform: "iQIYI",
|
|
75
|
+
synopsis: "Modern retelling of the classic Chinese legend. Bai Suzhen, a white snake spirit, falls in love with mortal scholar Xu Xian and opens a medical clinic.",
|
|
76
|
+
themeSong: { titleEn: "A Millennium's Wait", titleCn: "千年等一回", youtubeId: "-vf6jU96WI4" },
|
|
77
|
+
highlights: ["Drama Actress of the Year — iQIYI Scream Night 2019", "Official remake of the 1992 classic, aired in 10+ countries"],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "please-give-me-wings", titleEn: "Please Give Me a Pair of Wings", titleCn: "请赐我一双翅膀", year: 2019,
|
|
81
|
+
category: "modern-drama", role: "Lin Jiuge (林九歌)",
|
|
82
|
+
roleCn: "林九歌", episodes: 60, platform: "iQIYI",
|
|
83
|
+
synopsis: "A modern crime thriller. Lin Jiuge is wrongly imprisoned and must fight to prove her innocence while uncovering a larger conspiracy.",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: "legend-of-yunxi", titleEn: "Legend of Yunxi", titleCn: "芸汐传", year: 2018,
|
|
87
|
+
category: "historical-drama", role: "Han Yunxi (韩芸汐)",
|
|
88
|
+
roleCn: "韩芸汐", episodes: 48, rating: "9.0/10", platform: "iQIYI",
|
|
89
|
+
synopsis: "Breakthrough role. A talented female physician navigates palace intrigue and romance with Prince Long Feiye.",
|
|
90
|
+
featured: true, highlights: ["Breakthrough Actress — Weibo TV & Video Summit 2018", "Launched Ju Jingyi to top-tier actress status"],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "the-fallen-flowers", titleEn: "The Fallen Flowers", titleCn: "热血长安", year: 2017,
|
|
94
|
+
category: "historical-drama", role: "Shangguan Wan'er (上官婉儿)",
|
|
95
|
+
roleCn: "上官婉儿", episodes: 48, platform: "Youku",
|
|
96
|
+
synopsis: "Historical mystery drama set in the Tang Dynasty. Shangguan Wan'er solves cases alongside a team of investigators.",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "novoland-eagle-flag", titleEn: "Novoland: Eagle Flag", titleCn: "九州·天空城II", year: 2020,
|
|
100
|
+
category: "fantasy-drama", role: "Feng Ruotong (风如澈)",
|
|
101
|
+
roleCn: "风如澈", episodes: 34, platform: "Tencent Video",
|
|
102
|
+
synopsis: "Fantasy sequel. Feng Ruotong, a spirited girl, discovers her destiny in a world of warring fantasy kingdoms.",
|
|
103
|
+
},
|
|
104
|
+
];
|