tiktok-live-api 1.2.15 → 1.2.16
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/bin/demo.mjs +77 -71
- package/package.json +1 -1
package/bin/demo.mjs
CHANGED
|
@@ -11,75 +11,82 @@ import path from 'path';
|
|
|
11
11
|
const REACT_TEMPLATE = [
|
|
12
12
|
'"use client";',
|
|
13
13
|
"import React, { useEffect, useState, useRef } from 'react';",
|
|
14
|
-
"import { TikTokLive } from 'tiktok-live-api';",
|
|
15
14
|
"",
|
|
16
15
|
"export default function TikTokLiveComponent() {",
|
|
17
16
|
" const [events, setEvents] = useState([]);",
|
|
18
|
-
" const [username, setUsername] = useState('gbnews');",
|
|
19
|
-
" const [apiKey, setApiKey] = useState('demo_tiktokliveapi_public_2026');",
|
|
20
17
|
" const [inputUsername, setInputUsername] = useState('gbnews');",
|
|
18
|
+
" const [apiKey, setApiKey] = useState('demo_tiktokliveapi_public_2026');",
|
|
21
19
|
" const [connected, setConnected] = useState(false);",
|
|
22
|
-
" const
|
|
20
|
+
" const wsRef = useRef(null);",
|
|
23
21
|
"",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
22
|
+
" function addEvent(str) {",
|
|
23
|
+
" setEvents(prev => [...prev.slice(-50), str]);",
|
|
24
|
+
" }",
|
|
25
|
+
"",
|
|
26
|
+
" function connectStream(e) {",
|
|
27
|
+
" if (e) e.preventDefault();",
|
|
28
|
+
" if (wsRef.current) { wsRef.current.close(); wsRef.current = null; }",
|
|
27
29
|
" setEvents([]);",
|
|
28
30
|
" setConnected(false);",
|
|
29
|
-
" ",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
31
|
+
" const user = (inputUsername || '').replace(/^@/, '');",
|
|
32
|
+
" if (!user) return;",
|
|
33
|
+
" try {",
|
|
34
|
+
" const ws = new WebSocket('wss://api.tik.tools?uniqueId=' + user + '&apiKey=' + apiKey);",
|
|
35
|
+
" wsRef.current = ws;",
|
|
36
|
+
" ws.onopen = () => { setConnected(true); addEvent('Connected to @' + user); };",
|
|
37
|
+
" ws.onclose = () => { setConnected(false); wsRef.current = null; };",
|
|
38
|
+
" ws.onerror = () => { addEvent('WebSocket error'); };",
|
|
39
|
+
" ws.onmessage = (evt) => {",
|
|
40
|
+
" try {",
|
|
41
|
+
" const msg = JSON.parse(evt.data);",
|
|
42
|
+
" const t = msg.event || '';",
|
|
43
|
+
" const d = msg.data || {};",
|
|
44
|
+
" const u = d.user ? d.user.uniqueId : '';",
|
|
45
|
+
" if (t === 'chat') addEvent('[chat] ' + u + ': ' + d.comment);",
|
|
46
|
+
" else if (t === 'gift') addEvent('[gift] ' + u + ' sent ' + (d.giftName || 'a gift'));",
|
|
47
|
+
" else if (t === 'like') addEvent('[like] ' + u + ' liked');",
|
|
48
|
+
" else if (t === 'member') addEvent('[join] ' + u + ' joined');",
|
|
49
|
+
" else if (t === 'roomUserSeq') addEvent('[viewers] ' + (d.viewerCount || 0));",
|
|
50
|
+
" } catch (err) {}",
|
|
51
|
+
" };",
|
|
52
|
+
" } catch (err) { addEvent('Connection failed: ' + err.message); }",
|
|
53
|
+
" }",
|
|
44
54
|
"",
|
|
45
|
-
"
|
|
46
|
-
" e.preventDefault();",
|
|
47
|
-
" setUsername(inputUsername);",
|
|
48
|
-
" };",
|
|
55
|
+
" useEffect(() => { return () => { if (wsRef.current) wsRef.current.close(); }; }, []);",
|
|
49
56
|
"",
|
|
50
57
|
" return (",
|
|
51
58
|
" <div style={{ fontFamily: 'system-ui, sans-serif', maxWidth: 600, margin: '40px auto', border: '1px solid #e5e7eb', borderRadius: '12px', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)', background: '#fff' }}>",
|
|
52
59
|
" <div style={{ padding: '24px', borderBottom: '1px solid #e5e7eb' }}>",
|
|
53
|
-
" <h2 style={{ margin: '0 0 8px 0', fontSize: '1.5rem', fontWeight:
|
|
54
|
-
" <p style={{ margin: 0, fontSize: '0.875rem', color: '#
|
|
55
|
-
|
|
60
|
+
" <h2 style={{ margin: '0 0 8px 0', fontSize: '1.5rem', fontWeight: 700, color: '#111827' }}>TikTok Live SDK</h2>",
|
|
61
|
+
" <p style={{ margin: 0, fontSize: '0.875rem', color: '#4b5563' }}>",
|
|
62
|
+
' Get your own API key at <a href="https://tik.tools" target="_blank" style={{ color: \'#3b82f6\', textDecoration: \'none\' }}>tik.tools</a>',
|
|
56
63
|
" </p>",
|
|
57
64
|
" </div>",
|
|
58
65
|
" <div style={{ padding: '24px' }}>",
|
|
59
|
-
" <form onSubmit={
|
|
66
|
+
" <form onSubmit={connectStream} style={{ display: 'flex', flexDirection: 'column', gap: '16px', marginBottom: '24px' }}>",
|
|
60
67
|
" <div>",
|
|
61
|
-
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight:
|
|
62
|
-
|
|
68
|
+
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: 600, marginBottom: '6px', color: '#111827' }}>TikTok Username</label>",
|
|
69
|
+
' <input type="text" value={inputUsername} onChange={(e) => setInputUsername(e.target.value)} style={{ width: \'100%\', padding: \'8px 12px\', borderRadius: \'6px\', border: \'1px solid #d1d5db\', boxSizing: \'border-box\', color: \'#111827\' }} placeholder="e.g. gbnews" />',
|
|
63
70
|
" </div>",
|
|
64
71
|
" <div>",
|
|
65
|
-
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight:
|
|
66
|
-
|
|
67
|
-
" <p style={{ margin: '4px 0 0 0', fontSize: '0.75rem', color: '#
|
|
72
|
+
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: 600, marginBottom: '6px', color: '#111827' }}>API Key</label>",
|
|
73
|
+
' <input type="text" value={apiKey} onChange={(e) => setApiKey(e.target.value)} style={{ width: \'100%\', padding: \'8px 12px\', borderRadius: \'6px\', border: \'1px solid #d1d5db\', boxSizing: \'border-box\', fontFamily: \'monospace\', color: \'#111827\' }} />',
|
|
74
|
+
" <p style={{ margin: '4px 0 0 0', fontSize: '0.75rem', color: '#6b7280' }}>The demo key is rate-limited. Replace with your own key for production.</p>",
|
|
68
75
|
" </div>",
|
|
69
|
-
|
|
76
|
+
' <button type="submit" style={{ background: \'#111827\', color: \'#fff\', padding: \'10px 16px\', borderRadius: \'6px\', border: \'none\', fontWeight: 600, cursor: \'pointer\', fontSize: \'0.875rem\' }}>Connect Stream</button>',
|
|
70
77
|
" </form>",
|
|
71
78
|
" <div style={{ marginBottom: '16px', display: 'flex', alignItems: 'center', gap: '8px' }}>",
|
|
72
79
|
" <div style={{ width: 10, height: 10, borderRadius: '50%', background: connected ? '#10b981' : '#ef4444', transition: 'background 0.3s' }}></div>",
|
|
73
|
-
" <span style={{ fontSize: '0.875rem', color: '#
|
|
80
|
+
" <span style={{ fontSize: '0.875rem', color: '#111827', fontWeight: 600 }}>{connected ? 'Connected' : 'Disconnected'}</span>",
|
|
74
81
|
" </div>",
|
|
75
82
|
" <div style={{ height: 350, overflowY: 'auto', background: '#f9fafb', padding: '12px', borderRadius: '8px', border: '1px solid #e5e7eb', fontSize: '0.875rem', display: 'flex', flexDirection: 'column' }}>",
|
|
76
|
-
" {events.map((e, i) => <div key={i} style={{ padding: '6px 0', borderBottom: '1px solid #f3f4f6', wordBreak: 'break-word' }}>{e}</div>)}",
|
|
77
|
-
" {events.length === 0 && <div style={{ color: '#9ca3af', textAlign: 'center', margin: 'auto 0' }}>{connected ? 'Waiting for events...' : 'Connect to
|
|
83
|
+
" {events.map((e, i) => <div key={i} style={{ padding: '6px 0', borderBottom: '1px solid #f3f4f6', wordBreak: 'break-word', color: '#374151' }}>{e}</div>)}",
|
|
84
|
+
" {events.length === 0 && <div style={{ color: '#9ca3af', textAlign: 'center', margin: 'auto 0' }}>{connected ? 'Waiting for events...' : 'Connect to see events'}</div>}",
|
|
78
85
|
" </div>",
|
|
79
86
|
" </div>",
|
|
80
87
|
" </div>",
|
|
81
88
|
" );",
|
|
82
|
-
"}"
|
|
89
|
+
"}",
|
|
83
90
|
].join('\n') + "\n";
|
|
84
91
|
|
|
85
92
|
const VUE_TEMPLATE = [
|
|
@@ -466,47 +473,46 @@ function runScaffold(choice, targetDir, pm) {
|
|
|
466
473
|
'</template>'
|
|
467
474
|
].join('\n') + '\n');
|
|
468
475
|
} else {
|
|
469
|
-
console.log("\n " + B + "📦 Installing " + C.cyan + "tiktok-live-api" + B + " SDK..." + R + "\n");
|
|
470
|
-
execSync(installCmd, { cwd: fullPath, stdio: 'inherit' });
|
|
471
|
-
|
|
472
476
|
if (isNext) {
|
|
473
477
|
const compDir = path.join(fullPath, 'src', 'components');
|
|
474
478
|
if (!fs.existsSync(compDir)) fs.mkdirSync(compDir, { recursive: true });
|
|
475
479
|
fs.writeFileSync(path.join(compDir, 'TikTokLive.jsx'), REACT_TEMPLATE);
|
|
476
480
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
481
|
+
// Write page.js — create the directory if needed
|
|
482
|
+
const pageDir = path.join(fullPath, 'src', 'app');
|
|
483
|
+
if (!fs.existsSync(pageDir)) fs.mkdirSync(pageDir, { recursive: true });
|
|
484
|
+
fs.writeFileSync(path.join(pageDir, 'page.js'), [
|
|
485
|
+
"import TikTokLive from '@/components/TikTokLive';",
|
|
486
|
+
"",
|
|
487
|
+
"export default function Home() {",
|
|
488
|
+
" return (",
|
|
489
|
+
' <main style={{ minHeight: "100vh", background: "#f9fafb", paddingTop: "40px" }}>',
|
|
490
|
+
" <TikTokLive />",
|
|
491
|
+
" </main>",
|
|
492
|
+
" );",
|
|
493
|
+
"}",
|
|
494
|
+
].join('\n') + '\n');
|
|
491
495
|
} else if (isVite) {
|
|
492
496
|
const compDir = path.join(fullPath, 'src', 'components');
|
|
493
497
|
if (!fs.existsSync(compDir)) fs.mkdirSync(compDir, { recursive: true });
|
|
494
498
|
fs.writeFileSync(path.join(compDir, 'TikTokLive.jsx'), REACT_TEMPLATE);
|
|
495
499
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
500
|
+
// Write App.jsx — overwrite whatever create-vite generated (could be .jsx or .tsx)
|
|
501
|
+
const appContent = [
|
|
502
|
+
"import TikTokLive from './components/TikTokLive';",
|
|
503
|
+
"",
|
|
504
|
+
"export default function App() {",
|
|
505
|
+
" return (",
|
|
506
|
+
' <main style={{ minHeight: "100vh", background: "#f9fafb", paddingTop: "40px" }}>',
|
|
507
|
+
" <TikTokLive />",
|
|
508
|
+
" </main>",
|
|
509
|
+
" );",
|
|
510
|
+
"}",
|
|
511
|
+
].join('\n') + '\n';
|
|
512
|
+
fs.writeFileSync(path.join(fullPath, 'src', 'App.jsx'), appContent);
|
|
513
|
+
// Also remove App.tsx if it exists (create-vite sometimes uses TypeScript)
|
|
514
|
+
const appTsx = path.join(fullPath, 'src', 'App.tsx');
|
|
515
|
+
if (fs.existsSync(appTsx)) fs.unlinkSync(appTsx);
|
|
510
516
|
}
|
|
511
517
|
}
|
|
512
518
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiktok-live-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.16",
|
|
4
4
|
"description": "Unofficial TikTok LIVE API Client — Real-time chat, gifts, viewers, battles, and AI live captions from any TikTok livestream. Managed WebSocket API with 99.9% uptime.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|