AtlatestRepositorytube

tube / tree / src / tubemain.sgl

1;;; (tube main) - Entry point for tube CLI and MCP server.
2;;;
3;;; Dispatches between MCP server mode (`tube serve`) and CLI mode
4;;; (`tube <command> <args>`). Uses (sigil args) for CLI parsing.
5
6(define-library (tube main)
7 (import (sigil core)
8 (sigil string)
9 (sigil dict)
10 (sigil process)
11 (sigil args)
12 (sigil mcp server)
13 (sigil time)
14 (sigil oauth server)
15 (youtube oauth)
16 (twitch oauth)
17 (tube config)
18 (tube youtube)
19 (tube twitch)
20 (tube tools))
21 (export main)
22 (begin
24 (define (run-server config)
25 (let ((server (mcp-server name: "tube" version: "0.1.0")))
26 (register-tube-tools! server config)
27 (mcp-server-run server)))
29 ;; ============================================================
30 ;; Shared option builders
31 ;; ============================================================
33 (define (platform-option default)
34 (option name: 'platform short: #\p long: "platform"
35 value: "PLATFORM"
36 description: "Platform: youtube, twitch, or both"
37 choices: '("youtube" "twitch" "both")
38 default: default))
40 ;; ============================================================
41 ;; CLI Command Handlers
42 ;; ============================================================
44 (define (cli-upload config opts args)
45 (let ((file (if (pair? args) (car args) #f))
46 (title (alist-get 'title opts))
47 (description (alist-get 'description opts))
48 (privacy (alist-get 'privacy opts)))
49 (unless file
50 (display "Error: file path is required.\n")
51 (exit 1))
52 ;; Read file data
53 (let* ((port (open-binary-input-file file))
54 (data (read-bytevector-all port)))
55 (close-input-port port)
56 (let ((result (tube-upload-video config data title description privacy)))
57 (display (string-append
58 "Uploaded: " (youtube-video-title result) "\n"
59 "Video ID: " (youtube-video-id result) "\n"
60 "Privacy: " privacy "\n"))))))
62 (define (cli-videos config opts args)
63 (let* ((limit (alist-get 'limit opts))
64 (videos (tube-list-videos config limit)))
65 (if (null? videos)
66 (display "No videos found.\n")
67 (begin
68 (display (string-append
69 "Recent videos (" (number->string (length videos)) "):\n\n"))
70 (for-each (lambda (v)
71 (display (format-video v))
72 (display "\n\n"))
73 videos)))))
75 (define (cli-analytics config opts start-default end-default
76 now-timestamp)
77 (let* ((days (alist-get 'days opts))
78 (platform (alist-get 'platform opts))
79 (params #{ platform: platform
80 end_date: end-default })
81 (params (if days
82 (dict-set params days: days)
83 params)))
84 ;; Reuse the tool handler
85 (display (tool-analytics config params start-default end-default
86 now-timestamp))
87 (newline)))
89 (define (cli-schedule config opts)
90 (let ((params #{ platform: (alist-get 'platform opts) }))
91 (display (tool-schedule config params))
92 (newline)))
94 (define (cli-go-live config opts)
95 (let ((params #{ title: (alist-get 'title opts)
96 platform: (alist-get 'platform opts) }))
97 (display (tool-go-live config params))
98 (newline)))
100 (define (cli-chat config opts args)
101 (let ((message (if (pair? args)
102 (string-join args " ")
103 #f))
104 (platform (alist-get 'platform opts)))
105 (unless message
106 (display "Error: chat message is required.\n")
107 (exit 1))
108 (let ((params #{ message: message platform: platform }))
109 (display (tool-chat config params))
110 (newline))))
112 (define (cli-status config opts)
113 (let ((params #{ platform: (alist-get 'platform opts) }))
114 (display (tool-status config params))
115 (newline)))
117 ;; ============================================================
118 ;; Auth Command
119 ;; ============================================================
121 (define (cli-auth-youtube config)
122 (let ((client-id (tube-config-youtube-client-id config))
123 (client-secret (tube-config-youtube-client-secret config)))
124 (unless (and client-id client-secret)
125 (display "Error: YOUTUBE_CLIENT_ID and YOUTUBE_CLIENT_SECRET must be set.\n")
126 (exit 1))
127 (let* ((oauth-cfg (youtube-oauth-config client-id client-secret))
128 (tokens (oauth-run-authorization-flow oauth-cfg
129 (current-second))))
130 (youtube-save-tokens tokens)
131 (display "YouTube authorization successful. Tokens saved.\n"))))
133 (define (cli-auth-twitch config)
134 (let ((client-id (tube-config-twitch-client-id config))
135 (client-secret (tube-config-twitch-client-secret config)))
136 (unless (and client-id client-secret)
137 (display "Error: TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET must be set.\n")
138 (exit 1))
139 (let* ((oauth-cfg (twitch-oauth-config client-id client-secret))
140 (tokens (oauth-run-authorization-flow oauth-cfg
141 (current-second))))
142 (twitch-save-tokens tokens)
143 (display "Twitch authorization successful. Tokens saved.\n"))))
145 (define (cli-auth config opts args)
146 (let ((platform (if (pair? args) (car args) #f)))
147 (cond
148 ((equal? platform "youtube") (cli-auth-youtube config))
149 ((equal? platform "twitch") (cli-auth-twitch config))
150 (else
151 (display "Usage: tube auth <youtube|twitch>\n\n")
152 (display "Run the OAuth authorization flow for a platform.\n")
153 (display "Requires CLIENT_ID and CLIENT_SECRET env vars.\n")
154 (display "Tokens are stored in ~/.config/sigil/<service>/tokens.json\n")))))
156 ;; ============================================================
157 ;; CLI Definition
158 ;; ============================================================
160 (define (make-cli config start-default end-default now-ts)
161 (let ((default-plat (tube-config-default-platform config)))
162 (command
163 name: "tube"
164 description: "Video platform management tool (YouTube + Twitch)"
165 subcommands: (list
166 (command
167 name: "serve"
168 description: "Start MCP server"
169 handler: (lambda (opts args) (run-server config)))
171 (command
172 name: "upload"
173 description: "Upload video to YouTube"
174 options: (list
175 (option name: 'title short: #\t long: "title"
176 value: "TITLE" default: "Untitled"
177 description: "Video title")
178 (option name: 'description short: #\d long: "description"
179 value: "DESC" default: ""
180 description: "Video description")
181 (option name: 'privacy long: "privacy"
182 value: "PRIVACY" default: "private"
183 description: "Privacy status"
184 choices: '("public" "private" "unlisted")))
185 handler: (lambda (opts args) (cli-upload config opts args)))
187 (command
188 name: "videos"
189 description: "List recent YouTube videos"
190 options: (list
191 (option name: 'limit short: #\n long: "limit"
192 value: "N" default: 10
193 parse: string->number
194 description: "Number of videos to return"))
195 handler: (lambda (opts args) (cli-videos config opts args)))
197 (command
198 name: "analytics"
199 description: "Analytics summary"
200 options: (list
201 (option name: 'days long: "days"
202 value: "N" default: #f
203 parse: string->number
204 description: "Number of days to look back")
205 (platform-option default-plat))
206 handler: (lambda (opts args)
207 (cli-analytics config opts start-default
208 end-default now-ts)))
210 (command
211 name: "stream-schedule"
212 description: "Show upcoming streams"
213 options: (list (platform-option default-plat))
214 handler: (lambda (opts args) (cli-schedule config opts)))
216 (command
217 name: "go-live"
218 description: "Start a broadcast"
219 options: (list
220 (option name: 'title short: #\t long: "title"
221 value: "TITLE" default: "Live Stream"
222 description: "Stream title")
223 (platform-option default-plat))
224 handler: (lambda (opts args) (cli-go-live config opts)))
226 (command
227 name: "chat"
228 description: "Send chat message"
229 options: (list
230 (platform-option "twitch"))
231 handler: (lambda (opts args) (cli-chat config opts args)))
233 (command
234 name: "status"
235 description: "Platform overview"
236 options: (list (platform-option default-plat))
237 handler: (lambda (opts args) (cli-status config opts)))
239 (command
240 name: "auth"
241 description: "Authorize a platform via OAuth"
242 handler: (lambda (opts args) (cli-auth config opts args)))))))
244 ;; ============================================================
245 ;; Entry Point
246 ;; ============================================================
248 (define (main)
249 (let* ((config (load-tube-config))
250 (start-default (default-start-date))
251 (end-default (default-end-date))
252 (now-ts (default-now-timestamp))
253 (cli (make-cli config start-default end-default now-ts)))
254 (run-command cli (cdr (command-line)))))
256 ))