@zsukim/ctv-run 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 +277 -0
- package/dist/config.js +29 -0
- package/dist/firetv.js +67 -0
- package/dist/index.js +61 -0
- package/dist/platforms/firetv.js +119 -0
- package/dist/platforms/tizen.js +224 -0
- package/dist/platforms/vizio.js +162 -0
- package/dist/platforms/webos.js +150 -0
- package/dist/tizen.js +94 -0
- package/dist/util.js +35 -0
- package/dist/utils/config.js +20 -0
- package/dist/utils/ip.js +14 -0
- package/dist/utils/platform.js +29 -0
- package/dist/vizio.js +161 -0
- package/dist/webos.js +87 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# πΊ ctv-run
|
|
2
|
+
|
|
3
|
+
> React, Vue λ± **μΉ κΈ°μ λ‘ λ§λ TV μ±**μ Vizio, LG webOS, Fire TV, Samsung Tizenμ λ°°ν¬νκ³ μ€ννλ CLI λꡬμ
λλ€.
|
|
4
|
+
|
|
5
|
+
μ€λ§νΈ TV νλ«νΌλ§λ€ λ€λ₯Έ κ°λ° νκ²½ ꡬμΆκ³Ό μ± μ€ν κ³Όμ μ λ¨μΌ λͺ
λ Ήμ΄λ‘ μλνν©λλ€.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## π λͺ©μ°¨
|
|
10
|
+
|
|
11
|
+
1. [μ€ν λͺ¨λ κ°μ](#μ€ν-λͺ¨λ-κ°μ)
|
|
12
|
+
2. [ctv.config.json](#ctvconfign)
|
|
13
|
+
3. [νλ«νΌλ³ μ¬μ μ€λΉ](#νλ«νΌλ³-μ¬μ -μ€λΉ)
|
|
14
|
+
4. [νλ«νΌλ³ μ¬μ©λ²](#νλ«νΌλ³-μ¬μ©λ²)
|
|
15
|
+
5. [μ£Όμμ¬ν](#μ£Όμμ¬ν)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## μ€ν λͺ¨λ κ°μ
|
|
20
|
+
|
|
21
|
+
λͺ¨λ νλ«νΌμ λ κ°μ§ λͺ¨λλ₯Ό μ§μν©λλ€.
|
|
22
|
+
|
|
23
|
+
| λͺ¨λ | μ΅μ
| μ€λͺ
|
|
|
24
|
+
|------|------|------|
|
|
25
|
+
| **Live Mode** | (κΈ°λ³Έκ°) | κ°λ° μλ² URLμ TVμ μ£Όμ
. HMR μ§μ |
|
|
26
|
+
| **Static Mode** | `--target=dist` | λΉλ κ²°κ³Όλ¬Όμ TVμ μ§μ μ€μΉ |
|
|
27
|
+
|
|
28
|
+
> **Vizio**λ ꡬ쑰μ νμ URLμ΄ νμνλ―λ‘ Live Modeλ§ μ§μν©λλ€.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## ctv.config.json
|
|
33
|
+
|
|
34
|
+
νλ‘μ νΈ λ£¨νΈμ μμ±νλ©΄ CLI μ΅μ
μ μλ΅ν μ μμ΅λλ€. CLI μ΅μ
μ΄ νμ μ°μ ν©λλ€.
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"vizio": {
|
|
39
|
+
"ip": "192.168.11.27",
|
|
40
|
+
"url": "http://192.168.11.10:3300"
|
|
41
|
+
},
|
|
42
|
+
"fire": {
|
|
43
|
+
"ip": "192.168.11.20",
|
|
44
|
+
"package": "com.example.tvapp",
|
|
45
|
+
"url": "http://192.168.11.10:3300",
|
|
46
|
+
"adbPath": "/usr/local/bin/adb",
|
|
47
|
+
"androidAssetsPath": "/path/to/android/app/src/main/assets"
|
|
48
|
+
},
|
|
49
|
+
"tizen": {
|
|
50
|
+
"ip": "192.168.11.30",
|
|
51
|
+
"appId": "A123456789.MyApp"
|
|
52
|
+
},
|
|
53
|
+
"webos": {
|
|
54
|
+
"deviceName": "my-lg-tv",
|
|
55
|
+
"appId": "com.example.tvapp"
|
|
56
|
+
},
|
|
57
|
+
"common": {
|
|
58
|
+
"devServerPort": 3300
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Fields
|
|
64
|
+
|
|
65
|
+
**Vizio**
|
|
66
|
+
|
|
67
|
+
| Field | νμ | Description |
|
|
68
|
+
|-------|------|-------------|
|
|
69
|
+
| `ip` | β
| Vizio TV λ‘컬 IP |
|
|
70
|
+
| `url` | | TVμμ λ‘λν κ°λ° μλ² URL |
|
|
71
|
+
|
|
72
|
+
**Fire TV**
|
|
73
|
+
|
|
74
|
+
| Field | νμ | Description |
|
|
75
|
+
|-------|------|-------------|
|
|
76
|
+
| `ip` | β
| Fire TV λ‘컬 IP |
|
|
77
|
+
| `package` | β
| Android μ± ν¨ν€μ§λͺ
|
|
|
78
|
+
| `url` | | Live Modeμμ μ£Όμ
ν κ°λ° μλ² URL |
|
|
79
|
+
| `adbPath` | | adb μ€ν κ²½λ‘ (κΈ°λ³Έκ°: `adb`) |
|
|
80
|
+
| `androidAssetsPath` | Static Mode μ β
| dist νμΌμ΄ 볡μ¬λ Android `assets` ν΄λ μ λ κ²½λ‘ |
|
|
81
|
+
|
|
82
|
+
**Tizen**
|
|
83
|
+
|
|
84
|
+
| Field | νμ | Description |
|
|
85
|
+
|-------|------|-------------|
|
|
86
|
+
| `ip` | β
| Samsung Tizen TV λ‘컬 IP |
|
|
87
|
+
| `appId` | | Tizen μ± κ³ μ ID (μμΌλ©΄ μλ μμ±) |
|
|
88
|
+
|
|
89
|
+
**WebOS**
|
|
90
|
+
|
|
91
|
+
| Field | νμ | Description |
|
|
92
|
+
|-------|------|-------------|
|
|
93
|
+
| `deviceName` | β
| ares-cliμ λ±λ‘λ κΈ°κΈ° μ΄λ¦ |
|
|
94
|
+
| `appId` | | webOS μ± ID (κΈ°λ³Έκ°: `com.ctvrun.app`) |
|
|
95
|
+
|
|
96
|
+
**Common**
|
|
97
|
+
|
|
98
|
+
| Field | Description |
|
|
99
|
+
|-------|-------------|
|
|
100
|
+
| `devServerPort` | Live Modeμμ μ¬μ©ν κ°λ° μλ² ν¬νΈ (κΈ°λ³Έκ°: `3000`) |
|
|
101
|
+
|
|
102
|
+
> π‘ TV IPκ° κ°λ°μλ§λ€ λ€λ₯Ό μ μμΌλ―λ‘ `ctv.config.json`μ `.gitignore`μ μΆκ°νκ³ , `ctv.config.sample.json`μ μ μ₯μμ 곡μ νλ κ²μ κΆμ₯ν©λλ€.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## νλ«νΌλ³ μ¬μ μ€λΉ
|
|
107
|
+
|
|
108
|
+
### Vizio
|
|
109
|
+
|
|
110
|
+
Playwright Chromiumμ΄ νμν©λλ€.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npx playwright install chromium
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Fire TV
|
|
117
|
+
|
|
118
|
+
ADBκ° μ€μΉλμ΄ μμ΄μΌ νλ©°, TVμμ **κ°λ°μ μ΅μ
β ADB λλ²κΉ
**μ΄ νμ±νλμ΄ μμ΄μΌ ν©λλ€.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# μ°κ²° νμΈ
|
|
122
|
+
adb devices
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Static Mode(`--target=dist`) μ¬μ© μ μ± μ½λμ λ€μ μ€μ μ΄ νμν©λλ€.
|
|
126
|
+
|
|
127
|
+
**AndroidManifest.xml**
|
|
128
|
+
|
|
129
|
+
```xml
|
|
130
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
131
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
132
|
+
|
|
133
|
+
<application android:usesCleartextTraffic="true" ...>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**MainActivity.kt** β ADBλ‘ μ£Όμ
λ URL μ²λ¦¬
|
|
137
|
+
|
|
138
|
+
```kotlin
|
|
139
|
+
val intentUrl = intent.getStringExtra("TARGET_URL")
|
|
140
|
+
|
|
141
|
+
if (!intentUrl.isNullOrEmpty()) {
|
|
142
|
+
webView.loadUrl(intentUrl) // Live Mode
|
|
143
|
+
} else {
|
|
144
|
+
webView.loadUrl("file:///android_asset/index.html") // Static Mode
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Tizen
|
|
149
|
+
|
|
150
|
+
[Tizen Studio](https://developer.tizen.org/development/tizen-studio/download) μ€μΉ ν PATHλ₯Ό μ€μ ν©λλ€.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# ~/.zshrc λλ ~/.bash_profile
|
|
154
|
+
export TIZEN_STUDIO_HOME="$HOME/tizen-studio"
|
|
155
|
+
export PATH="$PATH:$TIZEN_STUDIO_HOME/tools/ide/bin:$TIZEN_STUDIO_HOME/tools"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
source ~/.zshrc
|
|
160
|
+
|
|
161
|
+
# μ€μΉ νμΈ
|
|
162
|
+
tizen version
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
μΈμ¦μ νλ‘νμ΄ μμΌλ©΄ 첫 μ€ν μ μλμΌλ‘ μμ±ν©λλ€.
|
|
166
|
+
|
|
167
|
+
### WebOS
|
|
168
|
+
|
|
169
|
+
[LG webOS SDK](https://webostv.developer.lge.com) μ€μΉ ν κΈ°κΈ°λ₯Ό λ±λ‘ν©λλ€.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# κΈ°κΈ° λ±λ‘ (μ΅μ΄ 1ν)
|
|
173
|
+
ares-setup-device
|
|
174
|
+
|
|
175
|
+
# λ±λ‘ νμΈ
|
|
176
|
+
ares-setup-device --list
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## νλ«νΌλ³ μ¬μ©λ² μμ
|
|
182
|
+
|
|
183
|
+
### Vizio
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# URL μ§μ μ§μ
|
|
187
|
+
ctv-run vizio --ip=192.168.11.27 --url=http://192.168.11.10:3300
|
|
188
|
+
|
|
189
|
+
# ν¬νΈλ§ μ§μ (λ‘컬 IP μλ κ°μ§)
|
|
190
|
+
ctv-run vizio --ip=192.168.11.27 --port=3300
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**μλ μ리**
|
|
194
|
+
|
|
195
|
+
Playwrightλ‘ Vizio μΉ λ°μ²λ₯Ό μλ μ‘°μνμ¬ νμ΄λ§(PIN μ
λ ₯) ν μ± URLμ μ£Όμ
ν©λλ€.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Fire TV
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Live Mode β κ°λ° μλ² URL μ£Όμ
|
|
203
|
+
ctv-run fire --url=http://192.168.11.10:3300
|
|
204
|
+
|
|
205
|
+
# Live Mode β ν¬νΈλ§ μ§μ
|
|
206
|
+
ctv-run fire --port=3300
|
|
207
|
+
|
|
208
|
+
# Static Mode β distλ₯Ό Android assetsμ λ³΅μ¬ ν λ‘컬 μ€ν
|
|
209
|
+
ctv-run fire --target=dist
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
> Static Modeλ `androidAssetsPath` μ€μ μ΄ νμμ
λλ€.
|
|
213
|
+
|
|
214
|
+
**μλ μ리**
|
|
215
|
+
|
|
216
|
+
- **Live Mode**: ADBλ‘ μ±μ μ€ννλ©° `TARGET_URL` extraλ₯Ό μ£Όμ
ν©λλ€.
|
|
217
|
+
- **Static Mode**: dist νμΌμ Android `assets` ν΄λμ 볡μ¬ν λ€ μ±μ μ€νν©λλ€. μ±μ `file:///android_asset/index.html`μ λ‘λν©λλ€.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### Tizen
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Live Mode β κ°λ° μλ²λ‘ 리λ€μ΄λ νΈνλ μ± μ€μΉ ν μ€ν
|
|
225
|
+
ctv-run tizen --ip=192.168.11.30
|
|
226
|
+
|
|
227
|
+
# Static Mode β distλ₯Ό .wgtλ‘ ν¨ν€μ§νμ¬ TVμ μ€μΉ
|
|
228
|
+
ctv-run tizen --ip=192.168.11.30 --target=dist
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**μλ μ리**
|
|
232
|
+
|
|
233
|
+
- **Live Mode**: κ°λ° μλ²λ‘ 리λ€μ΄λ νΈνλ `index.html`μ ν¬ν¨ν `.wgt`λ₯Ό μ€μΉν©λλ€.
|
|
234
|
+
- **Static Mode**: dist ν΄λλ₯Ό `.wgt`λ‘ ν¨ν€μ§νμ¬ TVμ μ€μΉν©λλ€.
|
|
235
|
+
|
|
236
|
+
`config.xml`μ΄ μμΌλ©΄ μλ μμ±λ©λλ€. 컀μ€ν°λ§μ΄μ§μ΄ νμνλ©΄ νλ‘μ νΈ λ£¨νΈμ `config.xml`μ μΆκ°νμΈμ.
|
|
237
|
+
|
|
238
|
+
λλ²κΉ
μ Chromeμμ `http://[TV_IP]:9222`λ‘ μ μν©λλ€. (TV μ€μ μμ λλ²κ·Έ λͺ¨λ νμ±ν νμ)
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### WebOS
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Live Mode β κ°λ° μλ²λ‘ 리λ€μ΄λ νΈνλ μ± μ€μΉ ν μ€ν
|
|
246
|
+
ctv-run webos --device=my-lg-tv
|
|
247
|
+
|
|
248
|
+
# Static Mode β distλ₯Ό .ipkλ‘ ν¨ν€μ§νμ¬ TVμ μ€μΉ
|
|
249
|
+
ctv-run webos --device=my-lg-tv --target=dist
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**μλ μ리**
|
|
253
|
+
|
|
254
|
+
- **Live Mode**: κ°λ° μλ²λ‘ 리λ€μ΄λ νΈνλ `index.html`μ ν¬ν¨ν `.ipk`λ₯Ό μ€μΉν©λλ€.
|
|
255
|
+
- **Static Mode**: dist ν΄λλ₯Ό `.ipk`λ‘ ν¨ν€μ§νμ¬ TVμ μ€μΉν©λλ€.
|
|
256
|
+
|
|
257
|
+
`appinfo.json`μ΄ μμΌλ©΄ μλ μμ±λ©λλ€.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## μ£Όμμ¬ν
|
|
262
|
+
|
|
263
|
+
### λ€νΈμν¬
|
|
264
|
+
|
|
265
|
+
κ°λ° PCμ TVλ **λμΌν Wi-Fi λλ μ μ λ€νΈμν¬**μ μ°κ²°λμ΄ μμ΄μΌ ν©λλ€.
|
|
266
|
+
|
|
267
|
+
### Live Mode λ‘λ© μλ
|
|
268
|
+
|
|
269
|
+
Vite κ°λ° μλ²λ HMRμ μν΄ λͺ¨λμ κ°λ³ μ μ‘νλ―λ‘ TV μ¬μμ λ°λΌ **μ΄κΈ° λ‘λ©μ 10~30μ΄ μ΄μ** 걸릴 μ μμ΅λλ€. μ±λ₯ νμΈμ΄ νμνλ€λ©΄ Static Modeλ₯Ό μ¬μ©νμΈμ.
|
|
270
|
+
|
|
271
|
+
### Tizen ν¬νΈ κΆν
|
|
272
|
+
|
|
273
|
+
`ctv-run tizen` μ€ν μ κΆν μ€λ₯κ° λ°μνλ©΄ `sudo`λ₯Ό λΆμ¬ μ€ννμΈμ.
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
sudo ctv-run tizen --ip=192.168.11.30
|
|
277
|
+
```
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CONFIG = void 0;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
dotenv_1.default.config();
|
|
9
|
+
// export function getTargetIp(platform: string) {
|
|
10
|
+
// const configPath = path.join(process.cwd(), 'ctv.config.json');
|
|
11
|
+
//
|
|
12
|
+
// // 1. μ€μ νμΌμ΄ μμΌλ©΄ μ½μ΄μ€κΈ°
|
|
13
|
+
// if (fs.existsSync(configPath)) {
|
|
14
|
+
// const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
15
|
+
// if (config.platforms?.[platform]?.ip) {
|
|
16
|
+
// return config.platforms[platform].ip;
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
//
|
|
20
|
+
// // 2. μ€μ νμΌμ΄ μμΌλ©΄ νκ²½λ³μλ κΈ°λ³Έκ° μ¬μ© (ν
μ€νΈμ©)
|
|
21
|
+
// return process.env.VIZIO_TV_IP || '0.0.0.0';
|
|
22
|
+
// }
|
|
23
|
+
exports.CONFIG = {
|
|
24
|
+
DIST_PATH: './dist',
|
|
25
|
+
PORT: 3000,
|
|
26
|
+
// .env νμΌμ TV_IP=192.168.x.x ννλ‘ μ μ₯νμΈμ
|
|
27
|
+
VIZIO_TV_IP: process.env.VIZIO_TV_IP || '0.0.0.0',
|
|
28
|
+
LAUNCHER_URL: 'https://vizio-pm.s3-us-west-1.amazonaws.com/conjure-launcher.html',
|
|
29
|
+
};
|
package/dist/firetv.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runFireTv = runFireTv;
|
|
13
|
+
const child_process_1 = require("child_process");
|
|
14
|
+
const util_1 = require("./util");
|
|
15
|
+
function runFireTv() {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
var _a, _b, _c;
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const config = (0, util_1.loadConfig)();
|
|
20
|
+
const getArg = (name) => { var _a; return (_a = args.find(arg => arg.startsWith(`--${name}=`))) === null || _a === void 0 ? void 0 : _a.split('=')[1]; };
|
|
21
|
+
const tvIp = getArg('ip') || ((_a = config.firetv) === null || _a === void 0 ? void 0 : _a.ip);
|
|
22
|
+
const pkg = getArg('package') || ((_b = config.firetv) === null || _b === void 0 ? void 0 : _b.package);
|
|
23
|
+
const targetArg = getArg('target'); // 'dist' λ±μ΄ λ€μ΄μ€λ©΄ λ²λ€ λͺ¨λλ‘ κ°μ£Ό
|
|
24
|
+
const activity = getArg('activity') || ((_c = config.firetv) === null || _c === void 0 ? void 0 : _c.activity) || '.MainActivity';
|
|
25
|
+
const appUrl = getArg('url') || `http://${(0, util_1.getLocalIp)()}:5173`;
|
|
26
|
+
if (!tvIp || !pkg) {
|
|
27
|
+
console.error(`\nβ Fire TV νμ μ€μ (ip, package)μ΄ λλ½λμμ΅λλ€!`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`-----------------------------------------`);
|
|
31
|
+
console.log(`π‘ Target TV IP : ${tvIp}`);
|
|
32
|
+
console.log(`π¦ Package Name : ${pkg}`);
|
|
33
|
+
if (targetArg) {
|
|
34
|
+
console.log(`π¦ Mode : π Bundle Mode (Local App)`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log(`π¦ Mode : π Live Mode (Remote URL)`);
|
|
38
|
+
console.log(`π App URL : ${appUrl}`);
|
|
39
|
+
}
|
|
40
|
+
console.log(`-----------------------------------------`);
|
|
41
|
+
try {
|
|
42
|
+
// 1. ADB μ°κ²°
|
|
43
|
+
console.log(`π ADB Connecting to ${tvIp}...`);
|
|
44
|
+
(0, child_process_1.execSync)(`adb connect ${tvIp}:5555`, { stdio: 'pipe' });
|
|
45
|
+
// 2. κΈ°μ‘΄ μ± μ’
λ£
|
|
46
|
+
console.log('π Force stopping existing process...');
|
|
47
|
+
(0, child_process_1.execSync)(`adb -s ${tvIp}:5555 shell am force-stop ${pkg}`);
|
|
48
|
+
// 3. μ€ν 컀맨λ 쑰립
|
|
49
|
+
const fullActivityPath = activity.startsWith('.') ? `${pkg}/${activity}` : `${pkg}/${pkg}${activity}`;
|
|
50
|
+
let launchCmd = `adb -s ${tvIp}:5555 shell am start -n ${fullActivityPath}`;
|
|
51
|
+
/**
|
|
52
|
+
* [ν΅μ¬ λ‘μ§]
|
|
53
|
+
* target μΈμκ° μμΌλ©΄(Live λͺ¨λ), TARGET_URL μλν
μ΄μ
μ μΆκ°ν΄μ 보λ
λλ€.
|
|
54
|
+
* target μΈμκ° μμΌλ©΄(Bundle λͺ¨λ), κ·Έλ₯ μ±λ§ μ€νν©λλ€.
|
|
55
|
+
*/
|
|
56
|
+
if (!targetArg) {
|
|
57
|
+
launchCmd += ` --es "TARGET_URL" "${appUrl}"`;
|
|
58
|
+
}
|
|
59
|
+
console.log('π± Launching App...');
|
|
60
|
+
(0, child_process_1.execSync)(launchCmd, { stdio: 'inherit' });
|
|
61
|
+
console.log(`\nβ
Success! Fire TV launch complete.`);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error(`\nβ Error: ${err.message}`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const firetv_1 = require("./platforms/firetv");
|
|
14
|
+
const tizen_1 = require("./platforms/tizen");
|
|
15
|
+
const vizio_1 = require("./platforms/vizio");
|
|
16
|
+
const webos_1 = require("./platforms/webos");
|
|
17
|
+
function main() {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
const platform = args[0]; // ctv-run [vizio | webos | firetv | tizen]
|
|
21
|
+
if (!platform || platform === '--help' || platform === '-h') {
|
|
22
|
+
console.log('\nπΊ CTV-RUN: Smart TV Deployment Tool');
|
|
23
|
+
console.log('-----------------------------------------');
|
|
24
|
+
console.log('μ¬μ©λ²: ctv-run [platform] [options]');
|
|
25
|
+
console.log('\nμ§μ νλ«νΌ:');
|
|
26
|
+
console.log(' vizio - Vizio SmartCast');
|
|
27
|
+
console.log(' webos - LG webOS TV');
|
|
28
|
+
console.log(' fire - Amazon Fire TV / Android TV');
|
|
29
|
+
console.log(' tizen - Samsung Tizen TV');
|
|
30
|
+
console.log('\nμμ:');
|
|
31
|
+
console.log(' ctv-run webos --device=lg-tv');
|
|
32
|
+
console.log(' ctv-run tizen --ip=192.168.0.10');
|
|
33
|
+
console.log('-----------------------------------------\n');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
switch (platform.toLowerCase()) {
|
|
38
|
+
case 'vizio':
|
|
39
|
+
yield (0, vizio_1.runVizio)();
|
|
40
|
+
break;
|
|
41
|
+
case 'webos':
|
|
42
|
+
yield (0, webos_1.runWebOS)();
|
|
43
|
+
break;
|
|
44
|
+
case 'fire':
|
|
45
|
+
yield (0, firetv_1.runFireTv)();
|
|
46
|
+
break;
|
|
47
|
+
case 'tizen':
|
|
48
|
+
yield (0, tizen_1.runTizen)();
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
console.error(`β μ§μνμ§ μλ νλ«νΌμ
λλ€: ${platform}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(`\nβ μ€ν μ€ μ€λ₯ λ°μ: ${err.message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
main();
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.runFireTv = runFireTv;
|
|
16
|
+
const child_process_1 = require("child_process");
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
const config_1 = require("../utils/config");
|
|
20
|
+
const ip_1 = require("../utils/ip");
|
|
21
|
+
const platform_1 = require("../utils/platform");
|
|
22
|
+
function runFireTv() {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
25
|
+
const args = process.argv.slice(2);
|
|
26
|
+
const config = (0, config_1.loadConfig)();
|
|
27
|
+
const getArg = (0, platform_1.makeArgParser)(args);
|
|
28
|
+
// μ€μ λ° μΈμ νμ±
|
|
29
|
+
const adbBin = getArg('adbPath') || ((_a = config.fire) === null || _a === void 0 ? void 0 : _a.adbPath) || 'adb';
|
|
30
|
+
const tvIp = getArg('ip') || ((_b = config.fire) === null || _b === void 0 ? void 0 : _b.ip);
|
|
31
|
+
const pkg = getArg('package') || ((_c = config.fire) === null || _c === void 0 ? void 0 : _c.package);
|
|
32
|
+
const activity = getArg('activity') || ((_d = config.fire) === null || _d === void 0 ? void 0 : _d.activity) || '.MainActivity';
|
|
33
|
+
const targetArg = getArg('target');
|
|
34
|
+
const androidAssetsPath = getArg('assetsPath') || ((_e = config.fire) === null || _e === void 0 ? void 0 : _e.androidAssetsPath);
|
|
35
|
+
// μ± URL κ²°μ (Live Mode μ μ©)
|
|
36
|
+
const userUrl = getArg('url') || ((_f = config.fire) === null || _f === void 0 ? void 0 : _f.url);
|
|
37
|
+
const port = getArg('port') || ((_g = config.fire) === null || _g === void 0 ? void 0 : _g.port) || ((_h = config.common) === null || _h === void 0 ? void 0 : _h.devServerPort) || 3000;
|
|
38
|
+
const appUrl = userUrl || `http://${(0, ip_1.getLocalIp)()}:${port}`;
|
|
39
|
+
if (!tvIp || !pkg) {
|
|
40
|
+
console.error(`\nβ Fire TV νμ μ€μ (ip, package)μ΄ λλ½λμμ΅λλ€!`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Static Mode: distλ₯Ό Android assetsμ λ³΅μ¬ (Tizen/WebOSμ λμΌν κ°λ
)
|
|
44
|
+
if (targetArg) {
|
|
45
|
+
if (!androidAssetsPath) {
|
|
46
|
+
console.error(`\nβ ctv.config.jsonμ 'androidAssetsPath'κ° μ€μ λμ΄ μμ§ μμ΅λλ€.`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const distPath = path_1.default.resolve(process.cwd(), targetArg);
|
|
50
|
+
const finalAssetsPath = path_1.default.isAbsolute(androidAssetsPath)
|
|
51
|
+
? androidAssetsPath
|
|
52
|
+
: path_1.default.resolve(process.cwd(), androidAssetsPath);
|
|
53
|
+
console.log(`-----------------------------------------`);
|
|
54
|
+
console.log(`π‘ Target TV IP : ${tvIp}`);
|
|
55
|
+
console.log(`π¦ Package Name : ${pkg}`);
|
|
56
|
+
console.log(`π ADB Binary : ${adbBin}`);
|
|
57
|
+
console.log(`π¦ Mode : π Static Mode (Assets Embedded)`);
|
|
58
|
+
console.log(`π Path : ${finalAssetsPath}`);
|
|
59
|
+
console.log(`-----------------------------------------`);
|
|
60
|
+
try {
|
|
61
|
+
const parentPath = path_1.default.dirname(finalAssetsPath);
|
|
62
|
+
if (!fs_1.default.existsSync(parentPath)) {
|
|
63
|
+
console.error(`\nβ κ²½λ‘ μ€λ₯: λΆλͺ¨ ν΄λκ° μ‘΄μ¬νμ§ μμ΅λλ€. (${parentPath})`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (fs_1.default.existsSync(finalAssetsPath)) {
|
|
67
|
+
(0, child_process_1.execSync)(`rm -rf "${finalAssetsPath}"/*`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
(0, child_process_1.execSync)(`mkdir -p "${finalAssetsPath}"`);
|
|
71
|
+
}
|
|
72
|
+
(0, child_process_1.execSync)(`cp -r "${distPath}"/* "${finalAssetsPath}"`);
|
|
73
|
+
console.log(`β
Asset copy complete.`);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error(`\nβ νμΌ λ³΅μ¬ μ€ μλ¬ λ°μ: ${err.message}`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Live Mode
|
|
82
|
+
console.log(`-----------------------------------------`);
|
|
83
|
+
console.log(`π‘ Target TV IP : ${tvIp}`);
|
|
84
|
+
console.log(`π¦ Package Name : ${pkg}`);
|
|
85
|
+
console.log(`π ADB Binary : ${adbBin}`);
|
|
86
|
+
console.log(`π¦ Mode : π Live Mode (Remote URL)`);
|
|
87
|
+
console.log(`π App URL : ${appUrl}`);
|
|
88
|
+
console.log(`-----------------------------------------`);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
// ADB μ°κ²°
|
|
92
|
+
console.log(`π ADB Connecting to ${tvIp}...`);
|
|
93
|
+
(0, child_process_1.execSync)(`${adbBin} connect ${tvIp}:5555`, { stdio: 'pipe' });
|
|
94
|
+
// κΈ°μ‘΄ μ± μ’
λ£
|
|
95
|
+
console.log('π Force stopping existing process...');
|
|
96
|
+
(0, child_process_1.execSync)(`${adbBin} -s ${tvIp}:5555 shell am force-stop ${pkg}`);
|
|
97
|
+
// μ€ν 컀맨λ μμ±
|
|
98
|
+
const fullActivityPath = activity.startsWith('.')
|
|
99
|
+
? `${pkg}/${activity}`
|
|
100
|
+
: activity;
|
|
101
|
+
let launchCmd = `${adbBin} -s ${tvIp}:5555 shell am start -n ${fullActivityPath}`;
|
|
102
|
+
// Live ModeμΌ λλ§ URL μ£Όμ
|
|
103
|
+
if (!targetArg) {
|
|
104
|
+
launchCmd += ` --es "TARGET_URL" "${appUrl}"`;
|
|
105
|
+
}
|
|
106
|
+
console.log('π± Launching App...');
|
|
107
|
+
(0, child_process_1.execSync)(launchCmd, { stdio: 'inherit' });
|
|
108
|
+
console.log(`\nβ
Success! Fire TV launch complete.`);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err.message.includes('ENOENT')) {
|
|
112
|
+
console.error(`\nβ Error: '${adbBin}' λͺ
λ Ήμ΄λ₯Ό μ°Ύμ μ μμ΅λλ€.`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.error(`\nβ Error: ${err.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|