···11+# ISC License
22+33+Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>
44+55+Permission to use, copy, modify, and/or distribute this software for any
66+purpose with or without fee is hereby granted, provided that the above
77+copyright notice and this permission notice appear in all copies.
88+99+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1010+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1111+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1212+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1313+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1414+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1515+PERFORMANCE OF THIS SOFTWARE.
+112
README.md
···11+# ocaml-peertube
22+33+An OCaml client library for the PeerTube video platform API, built on Eio for effect-based I/O.
44+55+## Features
66+77+- Browse, search, and fetch videos from any PeerTube instance
88+- Access channels, accounts, and playlists
99+- Retrieve server configuration and statistics
1010+- Automatic pagination support
1111+- Full JSON serialization with Jsont
1212+- Command-line client (`opeertube`) included
1313+1414+## Installation
1515+1616+### From source
1717+1818+```bash
1919+git clone https://git.recoil.org/anil.recoil.org/ocaml-peertube.git
2020+cd ocaml-peertube
2121+opam install . --deps-only
2222+dune build
2323+```
2424+2525+## Usage
2626+2727+### Library
2828+2929+```ocaml
3030+open Peertube
3131+3232+let () =
3333+ Eio_main.run @@ fun env ->
3434+ Eio.Switch.run @@ fun sw ->
3535+ let session = Requests.create ~sw env in
3636+ let client = Client.create ~session ~base_url:"https://video.example.com" in
3737+ let videos = Client.list_videos client ~count:10 () in
3838+ List.iter (fun v ->
3939+ Printf.printf "%s: %s\n" (Video.uuid v) (Video.name v)
4040+ ) (Paginated.data videos)
4141+```
4242+4343+### Command-line client
4444+4545+```bash
4646+# Browse videos
4747+opeertube browse -u https://video.example.com
4848+4949+# Search videos
5050+opeertube search -u https://video.example.com "search query"
5151+5252+# Get video details
5353+opeertube get -u https://video.example.com <uuid>
5454+5555+# List channels
5656+opeertube channels list -u https://video.example.com
5757+5858+# Get server info
5959+opeertube server info -u https://video.example.com
6060+6161+# JSON output
6262+opeertube browse -u https://video.example.com --json
6363+```
6464+6565+## API Coverage
6666+6767+### Videos
6868+- `Client.list_videos` - Browse videos with filtering and sorting
6969+- `Client.search_videos` - Full-text search with date/duration filters
7070+- `Client.fetch_video_details` - Get details for a specific video
7171+- `Client.fetch_channel_videos` - List videos from a channel
7272+- `Client.fetch_all_channel_videos` - Auto-paginate all channel videos
7373+7474+### Channels & Accounts
7575+- `Client.list_channels` / `Client.search_channels` / `Client.get_channel`
7676+- `Client.list_accounts` / `Client.get_account`
7777+- `Client.get_account_videos` / `Client.get_account_channels`
7878+7979+### Playlists
8080+- `Client.list_playlists` / `Client.search_playlists` / `Client.get_playlist`
8181+- `Client.get_playlist_videos` / `Client.get_account_playlists`
8282+8383+### Server
8484+- `Client.get_config` - Server configuration
8585+- `Client.get_stats` - Server statistics
8686+8787+## Documentation
8888+8989+Build locally with:
9090+9191+```bash
9292+dune build @doc
9393+open _build/default/_doc/_html/index.html
9494+```
9595+9696+## Development
9797+9898+### Building
9999+100100+```bash
101101+dune build
102102+```
103103+104104+### Formatting
105105+106106+```bash
107107+dune fmt
108108+```
109109+110110+## License
111111+112112+ISC License. See [LICENSE.md](LICENSE.md) for details.
···1111 Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ())
12121313let base_url_arg =
1414- let doc = "Base URL of the PeerTube instance (e.g., https://video.example.com)" in
1414+ let doc =
1515+ "Base URL of the PeerTube instance (e.g., https://video.example.com)"
1616+ in
1517 Arg.(required & opt (some string) None & info [ "u"; "url" ] ~docv:"URL" ~doc)
16181719let channel_arg =
···6466 Fmt.epr "Error: %s (HTTP %d)@." msg status;
6567 exit 1
66686969+let print_json codec value =
7070+ match Jsont_bytesrw.encode_string codec value with
7171+ | Ok s -> print_endline s
7272+ | Error e -> Fmt.epr "JSON encode error: %s@." e
7373+6774(* Video printing *)
68756976let print_video ?(json = false) (v : Peertube.Video.t) =
7070- if json then
7171- let json_str = Jsont_bytesrw.encode_string Peertube.Video.jsont v in
7272- match json_str with
7373- | Ok s -> print_endline s
7474- | Error e -> Fmt.epr "JSON encode error: %s@." e
7777+ if json then print_json Peertube.Video.jsont v
7578 else
7676- Fmt.pr "@[<v>%s@, UUID: %s@, ID: %d@, URL: %s@, Duration: %ds@, Views: %d@, Published: %a@, Tags: [%a]@]@."
7979+ Fmt.pr
8080+ "@[<v>%s@,\
8181+ \ UUID: %s@,\
8282+ \ ID: %d@,\
8383+ \ URL: %s@,\
8484+ \ Duration: %ds@,\
8585+ \ Views: %d@,\
8686+ \ Published: %a@,\
8787+ \ Tags: [%a]@]@."
7788 (Peertube.Video.name v) (Peertube.Video.uuid v) (Peertube.Video.id v)
7878- (Peertube.Video.url v) (Peertube.Video.duration v)
7979- (Peertube.Video.views v)
8080- (Ptime.pp_rfc3339 ()) (Peertube.Video.published_at v)
8181- Fmt.(list ~sep:(any ", ") string) (Peertube.Video.tags v)
8989+ (Peertube.Video.url v)
9090+ (Peertube.Video.duration v)
9191+ (Peertube.Video.views v) (Ptime.pp_rfc3339 ())
9292+ (Peertube.Video.published_at v)
9393+ Fmt.(list ~sep:(any ", ") string)
9494+ (Peertube.Video.tags v)
82958396let print_videos ?(json = false) videos =
8484- if json then begin
8585- let codec = Jsont.(list Peertube.Video.jsont) in
8686- let json_str = Jsont_bytesrw.encode_string codec videos in
8787- match json_str with
8888- | Ok s -> print_endline s
8989- | Error e -> Fmt.epr "JSON encode error: %s@." e
9090- end
9191- else
9292- List.iter (print_video ~json:false) videos
9797+ if json then print_json Jsont.(list Peertube.Video.jsont) videos
9898+ else List.iter (print_video ~json:false) videos
939994100(* Channel printing *)
95101···101107 (Peertube.Channel_summary.url c)
102108103109let print_channel ?(json = false) (c : Peertube.Channel.t) =
104104- if json then
105105- let json_str = Jsont_bytesrw.encode_string Peertube.Channel.jsont c in
106106- match json_str with
107107- | Ok s -> print_endline s
108108- | Error e -> Fmt.epr "JSON encode error: %s@." e
110110+ if json then print_json Peertube.Channel.jsont c
109111 else begin
110112 let summary = Peertube.Channel.summary c in
111111- Fmt.pr "@[<v>%s (@%s)@, ID: %d@, URL: %s@, Followers: %d@, Created: %a@]@."
113113+ Fmt.pr
114114+ "@[<v>%s (@%s)@, ID: %d@, URL: %s@, Followers: %d@, Created: %a@]@."
112115 (Peertube.Channel_summary.display_name summary)
113116 (Peertube.Channel_summary.name summary)
114117 (Peertube.Channel_summary.id summary)
115118 (Peertube.Channel_summary.url summary)
116119 (Peertube.Channel.followers_count c)
117117- (Ptime.pp_rfc3339 ()) (Peertube.Channel.created_at c);
118118- Option.iter (fun d -> Fmt.pr " Description: %s@." d)
120120+ (Ptime.pp_rfc3339 ())
121121+ (Peertube.Channel.created_at c);
122122+ Option.iter
123123+ (fun d -> Fmt.pr " Description: %s@." d)
119124 (Peertube.Channel.description c)
120125 end
121126122127let print_channels ?(json = false) channels =
123123- if json then begin
124124- let codec = Jsont.(list Peertube.Channel.jsont) in
125125- let json_str = Jsont_bytesrw.encode_string codec channels in
126126- match json_str with
127127- | Ok s -> print_endline s
128128- | Error e -> Fmt.epr "JSON encode error: %s@." e
129129- end
128128+ if json then print_json Jsont.(list Peertube.Channel.jsont) channels
130129 else
131131- List.iter (fun c -> print_channel_summary (Peertube.Channel.summary c)) channels
130130+ List.iter
131131+ (fun c -> print_channel_summary (Peertube.Channel.summary c))
132132+ channels
132133133134(* Account printing *)
134135···140141 (Peertube.Account_summary.url a)
141142142143let print_account ?(json = false) (a : Peertube.Account.t) =
143143- if json then
144144- let json_str = Jsont_bytesrw.encode_string Peertube.Account.jsont a in
145145- match json_str with
146146- | Ok s -> print_endline s
147147- | Error e -> Fmt.epr "JSON encode error: %s@." e
144144+ if json then print_json Peertube.Account.jsont a
148145 else begin
149146 let summary = Peertube.Account.summary a in
150150- Fmt.pr "@[<v>%s (@%s)@, ID: %d@, URL: %s@, Followers: %d@, Created: %a@]@."
147147+ Fmt.pr
148148+ "@[<v>%s (@%s)@, ID: %d@, URL: %s@, Followers: %d@, Created: %a@]@."
151149 (Peertube.Account_summary.display_name summary)
152150 (Peertube.Account_summary.name summary)
153151 (Peertube.Account_summary.id summary)
154152 (Peertube.Account_summary.url summary)
155153 (Peertube.Account.followers_count a)
156156- (Ptime.pp_rfc3339 ()) (Peertube.Account.created_at a);
157157- Option.iter (fun d -> Fmt.pr " Description: %s@." d)
154154+ (Ptime.pp_rfc3339 ())
155155+ (Peertube.Account.created_at a);
156156+ Option.iter
157157+ (fun d -> Fmt.pr " Description: %s@." d)
158158 (Peertube.Account.description a)
159159 end
160160161161let print_accounts ?(json = false) accounts =
162162- if json then begin
163163- let codec = Jsont.(list Peertube.Account.jsont) in
164164- let json_str = Jsont_bytesrw.encode_string codec accounts in
165165- match json_str with
166166- | Ok s -> print_endline s
167167- | Error e -> Fmt.epr "JSON encode error: %s@." e
168168- end
162162+ if json then print_json Jsont.(list Peertube.Account.jsont) accounts
169163 else
170170- List.iter (fun a -> print_account_summary (Peertube.Account.summary a)) accounts
164164+ List.iter
165165+ (fun a -> print_account_summary (Peertube.Account.summary a))
166166+ accounts
171167172168(* Playlist printing *)
173169174170let print_playlist ?(json = false) (p : Peertube.Playlist.t) =
175175- if json then
176176- let json_str = Jsont_bytesrw.encode_string Peertube.Playlist.jsont p in
177177- match json_str with
178178- | Ok s -> print_endline s
179179- | Error e -> Fmt.epr "JSON encode error: %s@." e
171171+ if json then print_json Peertube.Playlist.jsont p
180172 else
181181- Fmt.pr "@[<v>%s@, UUID: %s@, ID: %d@, Videos: %d@, URL: %s@, Created: %a@]@."
173173+ Fmt.pr
174174+ "@[<v>%s@,\
175175+ \ UUID: %s@,\
176176+ \ ID: %d@,\
177177+ \ Videos: %d@,\
178178+ \ URL: %s@,\
179179+ \ Created: %a@]@."
182180 (Peertube.Playlist.display_name p)
183183- (Peertube.Playlist.uuid p)
184184- (Peertube.Playlist.id p)
181181+ (Peertube.Playlist.uuid p) (Peertube.Playlist.id p)
185182 (Peertube.Playlist.videos_length p)
186186- (Peertube.Playlist.url p)
187187- (Ptime.pp_rfc3339 ()) (Peertube.Playlist.created_at p)
183183+ (Peertube.Playlist.url p) (Ptime.pp_rfc3339 ())
184184+ (Peertube.Playlist.created_at p)
188185189186let print_playlists ?(json = false) playlists =
190190- if json then begin
191191- let codec = Jsont.(list Peertube.Playlist.jsont) in
192192- let json_str = Jsont_bytesrw.encode_string codec playlists in
193193- match json_str with
194194- | Ok s -> print_endline s
195195- | Error e -> Fmt.epr "JSON encode error: %s@." e
196196- end
197197- else
198198- List.iter (print_playlist ~json:false) playlists
187187+ if json then print_json Jsont.(list Peertube.Playlist.jsont) playlists
188188+ else List.iter (print_playlist ~json:false) playlists
199189200190(* Video commands *)
201191···207197 let client = Peertube.Client.create ~session ~base_url in
208198 if all then begin
209199 let videos =
210210- Peertube.Client.fetch_all_channel_videos client ?max_pages ~page_size:count
211211- ~channel ()
200200+ Peertube.Client.fetch_all_channel_videos client ?max_pages
201201+ ~page_size:count ~channel ()
212202 in
213203 Fmt.pr "Found %d videos@.@." (List.length videos);
214204 print_videos ~json videos
···219209 in
220210 Fmt.pr "Showing %d of %d videos (offset %d)@.@."
221211 (List.length (Peertube.Paginated.data response))
222222- (Peertube.Paginated.total response) start;
212212+ (Peertube.Paginated.total response)
213213+ start;
223214 print_videos ~json (Peertube.Paginated.data response)
224215 end
225216···240231 let response = Peertube.Client.list_videos client ~count ~start () in
241232 Fmt.pr "Showing %d of %d videos (offset %d)@.@."
242233 (List.length (Peertube.Paginated.data response))
243243- (Peertube.Paginated.total response) start;
234234+ (Peertube.Paginated.total response)
235235+ start;
244236 print_videos ~json (Peertube.Paginated.data response)
245237246238let browse_videos_cmd =
···248240 let info = Cmd.info "browse" ~doc in
249241 Cmd.v info
250242 Term.(
251251- const browse_videos $ setup_log_term $ base_url_arg $ count_arg $ start_arg
252252- $ json_flag)
243243+ const browse_videos $ setup_log_term $ base_url_arg $ count_arg
244244+ $ start_arg $ json_flag)
253245254246let search_videos () base_url query count start json =
255247 handle_api_error @@ fun () ->
···257249 Eio.Switch.run @@ fun sw ->
258250 let session = Requests.create ~sw env in
259251 let client = Peertube.Client.create ~session ~base_url in
260260- let response =
261261- Peertube.Client.search_videos client ~query ~count ~start ()
262262- in
252252+ let response = Peertube.Client.search_videos client ~query ~count ~start () in
263253 Fmt.pr "Found %d results for '%s' (showing %d, offset %d)@.@."
264264- (Peertube.Paginated.total response) query
265265- (List.length (Peertube.Paginated.data response)) start;
254254+ (Peertube.Paginated.total response)
255255+ query
256256+ (List.length (Peertube.Paginated.data response))
257257+ start;
266258 print_videos ~json (Peertube.Paginated.data response)
267259268260let search_videos_cmd =
···270262 let info = Cmd.info "search" ~doc in
271263 Cmd.v info
272264 Term.(
273273- const search_videos $ setup_log_term $ base_url_arg $ query_arg $ count_arg
274274- $ start_arg $ json_flag)
265265+ const search_videos $ setup_log_term $ base_url_arg $ query_arg
266266+ $ count_arg $ start_arg $ json_flag)
275267276268let get_video () base_url uuid json =
277269 handle_api_error @@ fun () ->
···286278 let doc = "Get details for a specific video by UUID" in
287279 let info = Cmd.info "get" ~doc in
288280 Cmd.v info
289289- Term.(const get_video $ setup_log_term $ base_url_arg $ uuid_arg $ json_flag)
281281+ Term.(
282282+ const get_video $ setup_log_term $ base_url_arg $ uuid_arg $ json_flag)
290283291284let download_thumbnail () base_url uuid output =
292285 handle_api_error @@ fun () ->
···319312 Eio.Switch.run @@ fun sw ->
320313 let session = Requests.create ~sw env in
321314 let client = Peertube.Client.create ~session ~base_url in
322322- let response =
323323- Peertube.Client.list_channels client ~count ~start ()
324324- in
315315+ let response = Peertube.Client.list_channels client ~count ~start () in
325316 Fmt.pr "Showing %d of %d channels (offset %d)@.@."
326317 (List.length (Peertube.Paginated.data response))
327327- (Peertube.Paginated.total response) start;
318318+ (Peertube.Paginated.total response)
319319+ start;
328320 print_channels ~json (Peertube.Paginated.data response)
329321330322let list_channels_cmd =
···332324 let info = Cmd.info "list" ~doc in
333325 Cmd.v info
334326 Term.(
335335- const list_channels $ setup_log_term $ base_url_arg $ count_arg $ start_arg
336336- $ json_flag)
327327+ const list_channels $ setup_log_term $ base_url_arg $ count_arg
328328+ $ start_arg $ json_flag)
337329338330let search_channels () base_url query count start json =
339331 handle_api_error @@ fun () ->
···345337 Peertube.Client.search_channels client ~query ~count ~start ()
346338 in
347339 Fmt.pr "Found %d channels for '%s' (showing %d, offset %d)@.@."
348348- (Peertube.Paginated.total response) query
349349- (List.length (Peertube.Paginated.data response)) start;
340340+ (Peertube.Paginated.total response)
341341+ query
342342+ (List.length (Peertube.Paginated.data response))
343343+ start;
350344 print_channels ~json (Peertube.Paginated.data response)
351345352346let search_channels_cmd =
···386380 Eio.Switch.run @@ fun sw ->
387381 let session = Requests.create ~sw env in
388382 let client = Peertube.Client.create ~session ~base_url in
389389- let response =
390390- Peertube.Client.list_accounts client ~count ~start ()
391391- in
383383+ let response = Peertube.Client.list_accounts client ~count ~start () in
392384 Fmt.pr "Showing %d of %d accounts (offset %d)@.@."
393385 (List.length (Peertube.Paginated.data response))
394394- (Peertube.Paginated.total response) start;
386386+ (Peertube.Paginated.total response)
387387+ start;
395388 print_accounts ~json (Peertube.Paginated.data response)
396389397390let list_accounts_cmd =
···399392 let info = Cmd.info "list" ~doc in
400393 Cmd.v info
401394 Term.(
402402- const list_accounts $ setup_log_term $ base_url_arg $ count_arg $ start_arg
403403- $ json_flag)
395395+ const list_accounts $ setup_log_term $ base_url_arg $ count_arg
396396+ $ start_arg $ json_flag)
404397405398let get_account () base_url handle json =
406399 handle_api_error @@ fun () ->
···429422 in
430423 Fmt.pr "Showing %d of %d videos (offset %d)@.@."
431424 (List.length (Peertube.Paginated.data response))
432432- (Peertube.Paginated.total response) start;
425425+ (Peertube.Paginated.total response)
426426+ start;
433427 print_videos ~json (Peertube.Paginated.data response)
434428435429let get_account_videos_cmd =
···453447 Eio.Switch.run @@ fun sw ->
454448 let session = Requests.create ~sw env in
455449 let client = Peertube.Client.create ~session ~base_url in
456456- let response =
457457- Peertube.Client.list_playlists client ~count ~start ()
458458- in
450450+ let response = Peertube.Client.list_playlists client ~count ~start () in
459451 Fmt.pr "Showing %d of %d playlists (offset %d)@.@."
460452 (List.length (Peertube.Paginated.data response))
461461- (Peertube.Paginated.total response) start;
453453+ (Peertube.Paginated.total response)
454454+ start;
462455 print_playlists ~json (Peertube.Paginated.data response)
463456464457let list_playlists_cmd =
···479472 Peertube.Client.search_playlists client ~query ~count ~start ()
480473 in
481474 Fmt.pr "Found %d playlists for '%s' (showing %d, offset %d)@.@."
482482- (Peertube.Paginated.total response) query
483483- (List.length (Peertube.Paginated.data response)) start;
475475+ (Peertube.Paginated.total response)
476476+ query
477477+ (List.length (Peertube.Paginated.data response))
478478+ start;
484479 print_playlists ~json (Peertube.Paginated.data response)
485480486481let search_playlists_cmd =
···518513 in
519514 Fmt.pr "Showing %d of %d playlist elements (offset %d)@.@."
520515 (List.length (Peertube.Paginated.data response))
521521- (Peertube.Paginated.total response) start;
516516+ (Peertube.Paginated.total response)
517517+ start;
522518 List.iter
523519 (fun (e : Peertube.Playlist.Element.t) ->
524520 match Peertube.Playlist.Element.video e with
···540536 let doc = "Playlist operations" in
541537 let info = Cmd.info "playlists" ~doc in
542538 Cmd.group info
543543- [ list_playlists_cmd; search_playlists_cmd; get_playlist_cmd;
544544- get_playlist_videos_cmd ]
539539+ [
540540+ list_playlists_cmd;
541541+ search_playlists_cmd;
542542+ get_playlist_cmd;
543543+ get_playlist_videos_cmd;
544544+ ]
545545546546(* Server commands *)
547547···552552 let session = Requests.create ~sw env in
553553 let client = Peertube.Client.create ~session ~base_url in
554554 let config = Peertube.Client.get_config client () in
555555- if json then
556556- let json_str =
557557- Jsont_bytesrw.encode_string Peertube.Server_config.jsont config
558558- in
559559- match json_str with
560560- | Ok s -> print_endline s
561561- | Error e -> Fmt.epr "JSON encode error: %s@." e
555555+ if json then print_json Peertube.Server_config.jsont config
562556 else begin
563557 let instance = Peertube.Server_config.instance config in
564558 Fmt.pr
565565- "@[<v>Instance: %s@, %s@, Version: %s@, Signup allowed: %b@, \
566566- Transcoding: %b@]@."
559559+ "@[<v>Instance: %s@,\
560560+ \ %s@,\
561561+ \ Version: %s@,\
562562+ \ Signup allowed: %b@,\
563563+ \ Transcoding: %b@]@."
567564 (Peertube.Instance_info.name instance)
568565 (Peertube.Instance_info.short_description instance)
569566 (Peertube.Server_config.server_version config)
···584581 let session = Requests.create ~sw env in
585582 let client = Peertube.Client.create ~session ~base_url in
586583 let stats = Peertube.Client.get_stats client () in
587587- if json then
588588- let json_str =
589589- Jsont_bytesrw.encode_string Peertube.Server_stats.jsont stats
590590- in
591591- match json_str with
592592- | Ok s -> print_endline s
593593- | Error e -> Fmt.epr "JSON encode error: %s@." e
584584+ if json then print_json Peertube.Server_stats.jsont stats
594585 else begin
595586 Fmt.pr
596596- "@[<v>Users: %d (daily active: %d, weekly: %d, monthly: %d)@,Local \
597597- videos: %d (views: %d)@,Total videos: %d@,Local channels: %d@,Local \
598598- playlists: %d@,Instance followers: %d / following: %d@]@."
587587+ "@[<v>Users: %d (daily active: %d, weekly: %d, monthly: %d)@,\
588588+ Local videos: %d (views: %d)@,\
589589+ Total videos: %d@,\
590590+ Local channels: %d@,\
591591+ Local playlists: %d@,\
592592+ Instance followers: %d / following: %d@]@."
599593 (Peertube.Server_stats.total_users stats)
600594 (Peertube.Server_stats.total_daily_active_users stats)
601595 (Peertube.Server_stats.total_weekly_active_users stats)
···626620 let doc = "PeerTube API command-line client" in
627621 let info = Cmd.info "opeertube" ~version:"0.1.0" ~doc in
628622 Cmd.group info
629629- [ browse_videos_cmd; search_videos_cmd; get_video_cmd;
630630- list_channel_videos_cmd; download_thumbnail_cmd; channels_cmd;
631631- accounts_cmd; playlists_cmd; server_cmd ]
623623+ [
624624+ browse_videos_cmd;
625625+ search_videos_cmd;
626626+ get_video_cmd;
627627+ list_channel_videos_cmd;
628628+ download_thumbnail_cmd;
629629+ channels_cmd;
630630+ accounts_cmd;
631631+ playlists_cmd;
632632+ server_cmd;
633633+ ]
632634633635let () = exit (Cmd.eval main_cmd)
+7-3
dune-project
···3344(generate_opam_files true)
5566-(source (github avsm/ocaml-peertube))
66+(source (uri "https://git.recoil.org/anil.recoil.org/ocaml-peertube"))
77(license ISC)
88(authors "Anil Madhavapeddy")
99(maintainers "anil@recoil.org")
1010+(homepage "https://git.recoil.org/anil.recoil.org/ocaml-peertube")
1111+(bug_reports "https://git.recoil.org/anil.recoil.org/ocaml-peertube/issues")
10121113(package
1214 (name peertube)
1315 (synopsis "PeerTube API client for OCaml using Eio")
1414- (description "An OCaml client library for the PeerTube video platform API, built on Eio for effect-based I/O")
1616+ (description
1717+ "An OCaml client library for the PeerTube video platform API, built on Eio for effect-based I/O. Includes a command-line client (opeertube) for browsing videos, channels, accounts, and playlists.")
1518 (depends
1619 (ocaml (>= 5.1.0))
1720 (eio (>= 1.0))
···2124 (ptime (>= 1.0))
2225 (fmt (>= 0.9))
2326 (logs (>= 0.7))
2424- (cmdliner (>= 1.2))))
2727+ (cmdliner (>= 1.2))
2828+ (odoc :with-doc)))
+326-264
lib/peertube.mli
···11(** PeerTube API client for OCaml.
2233 This library provides a typed client for the
44- {{:https://docs.joinpeertube.org/api-rest-reference.html}PeerTube video platform API},
55- using {{:https://github.com/ocaml-multicore/eio}Eio} for effect-based I/O
66- and {{:https://erratique.ch/software/jsont}jsont} for JSON serialization.
44+ {{:https://docs.joinpeertube.org/api-rest-reference.html}PeerTube video
55+ platform API}, using {{:https://github.com/ocaml-multicore/eio}Eio} for
66+ effect-based I/O and {{:https://erratique.ch/software/jsont}jsont} for JSON
77+ serialization.
7889 {1 Quick Start}
910···18191920 (* List recent videos *)
2021 let videos = Client.list_videos client () in
2121- List.iter (fun v ->
2222- Printf.printf "%s (%s)\n" (Video.name v) (Video.uuid v)
2323- ) (Paginated.data videos)
2222+ List.iter
2323+ (fun v -> Printf.printf "%s (%s)\n" (Video.name v) (Video.uuid v))
2424+ (Paginated.data videos)
2425 ]}
25262627 {1 Module Organization}
27282828- The library is organized into focused modules, each with an abstract type [t],
2929- a JSON codec [jsont], accessors, and a pretty printer [pp]:
2929+ The library is organized into focused modules, each with an abstract type
3030+ [t], a JSON codec [jsont], accessors, and a pretty printer [pp]:
30313132 {2 Common Types}
3233 - {!Labeled} - ID-label pairs for categories, licences, languages
···4445 - {!Video} - Video records with metadata
45464647 {2 Playlists}
4747- - {!Playlist} - Video playlists with nested {!Playlist.Privacy}, {!Playlist.Type}, and {!Playlist.Element}
4848+ - {!Playlist} - Video playlists with nested {!Playlist.Privacy},
4949+ {!Playlist.Type}, and {!Playlist.Element}
48504951 {2 Server Information}
5052 - {!Instance_info} - Instance name and description
···5961(** Labeled values with ID and display label.
60626163 Used for categories, licences, languages, and other enumerated values
6262- returned by the PeerTube API. Each labeled value has an identifier
6363- and a human-readable label. *)
6464+ returned by the PeerTube API. Each labeled value has an identifier and a
6565+ human-readable label. *)
6466module Labeled : sig
6565- (** A labeled value with an identifier and human-readable label. *)
6667 type 'a t
6868+ (** A labeled value with an identifier and human-readable label. *)
67696868- (** [make ~id ~label] creates a labeled value. *)
6970 val make : id:'a -> label:string -> 'a t
7171+ (** [make ~id ~label] creates a labeled value. *)
70727171- (** [id t] returns the identifier. *)
7273 val id : 'a t -> 'a
7474+ (** [id t] returns the identifier. *)
73757676+ val label : 'a t -> string
7477 (** [label t] returns the human-readable label. *)
7575- val label : 'a t -> string
76787979+ val int_jsont : int t Jsont.t
7780 (** JSON codec for labeled values with integer IDs. *)
7878- val int_jsont : int t Jsont.t
79818080- (** JSON codec for labeled values with string IDs. *)
8182 val string_jsont : string t Jsont.t
8383+ (** JSON codec for labeled values with string IDs. *)
82848383- (** [pp pp_id] is a pretty printer for labeled values, using [pp_id] for the identifier. *)
8485 val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit
8686+ (** [pp pp_id] is a pretty printer for labeled values, using [pp_id] for the
8787+ identifier. *)
8588end
86898790(** Video privacy levels.
88918989- PeerTube videos can have different privacy settings that control
9090- who can view them. *)
9292+ PeerTube videos can have different privacy settings that control who can
9393+ view them. *)
9194module Privacy : sig
9295 (** Video privacy level.
9396 - [Public] - Visible to everyone
···9699 - [Internal] - Only visible to instance users *)
97100 type t = Public | Unlisted | Private | Internal
981019999- (** [to_int t] converts privacy to its API integer representation. *)
100102 val to_int : t -> int
103103+ (** [to_int t] converts privacy to its API integer representation. *)
101104102102- (** [of_int n] converts an API integer to privacy level. *)
103105 val of_int : int -> t
106106+ (** [of_int n] converts an API integer to privacy level. *)
104107105105- (** JSON codec for privacy. *)
106108 val jsont : t Jsont.t
109109+ (** JSON codec for privacy. *)
107110108108- (** Pretty printer for privacy. *)
109111 val pp : Format.formatter -> t -> unit
112112+ (** Pretty printer for privacy. *)
110113end
111114112115(** Video sort options for API queries.
113116114114- When listing or searching videos, you can specify how results should
115115- be sorted. *)
117117+ When listing or searching videos, you can specify how results should be
118118+ sorted. *)
116119module Video_sort : sig
117120 (** Video sort order.
118121 - [Newest] - Most recently published first
···125128 - [Best] - Best match (for search) *)
126129 type t = Newest | Oldest | Views | Likes | Trending | Hot | Random | Best
127130131131+ val to_string : t -> string
128132 (** [to_string t] converts sort option to API query string. *)
129129- val to_string : t -> string
130133134134+ val pp : Format.formatter -> t -> unit
131135 (** Pretty printer for sort options. *)
132132- val pp : Format.formatter -> t -> unit
133136end
134137135138(** Paginated API responses.
136139137137- Most list endpoints return paginated results with a total count
138138- and a page of data. Use [count] and [start] parameters in API
139139- calls to navigate through pages. *)
140140+ Most list endpoints return paginated results with a total count and a page
141141+ of data. Use [count] and [start] parameters in API calls to navigate through
142142+ pages. *)
140143module Paginated : sig
141141- (** A paginated response containing total count and a page of data. *)
142144 type 'a t
145145+ (** A paginated response containing total count and a page of data. *)
143146147147+ val make : total:int -> data:'a list -> 'a t
144148 (** [make ~total ~data] creates a paginated response. *)
145145- val make : total:int -> data:'a list -> 'a t
146149150150+ val total : 'a t -> int
147151 (** [total t] returns the total number of items available across all pages. *)
148148- val total : 'a t -> int
149152150150- (** [data t] returns the items in this page. *)
151153 val data : 'a t -> 'a list
154154+ (** [data t] returns the items in this page. *)
152155153153- (** [jsont ~kind item_jsont] creates a JSON codec for paginated responses
154154- of items encoded with [item_jsont]. *)
155156 val jsont : kind:string -> 'a Jsont.t -> 'a t Jsont.t
157157+ (** [jsont ~kind item_jsont] creates a JSON codec for paginated responses of
158158+ items encoded with [item_jsont]. *)
156159157157- (** [pp pp_item] is a pretty printer for paginated responses. *)
158160 val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit
161161+ (** [pp pp_item] is a pretty printer for paginated responses. *)
159162end
160163161164(** {1 Account Types} *)
···163166(** Summary of a PeerTube account.
164167165168 Account summaries are embedded in other responses (videos, channels, etc.)
166166- and contain basic identifying information. For full account details,
167167- use {!Client.get_account}. *)
169169+ and contain basic identifying information. For full account details, use
170170+ {!Client.get_account}. *)
168171module Account_summary : sig
172172+ type t
169173 (** Account summary type. *)
170170- type t
171174172172- (** Create an account summary. *)
173175 val make :
174176 id:int ->
175177 name:string ->
···178180 host:string ->
179181 avatar_path:string option ->
180182 t
183183+ (** Create an account summary. *)
181184185185+ val id : t -> int
182186 (** Numeric account ID. *)
183183- val id : t -> int
184187185185- (** Account name (handle without host, e.g., "username"). *)
186188 val name : t -> string
189189+ (** Account name (handle without host, e.g., "username"). *)
187190188188- (** Human-readable display name. *)
189191 val display_name : t -> string
192192+ (** Human-readable display name. *)
190193191191- (** Full account URL. *)
192194 val url : t -> string
195195+ (** Full account URL. *)
193196197197+ val host : t -> string
194198 (** Instance host (e.g., "framatube.org"). *)
195195- val host : t -> string
196199200200+ val avatar_path : t -> string option
197201 (** Avatar image path (relative to instance URL). *)
198198- val avatar_path : t -> string option
199202200200- (** JSON codec. *)
201203 val jsont : t Jsont.t
204204+ (** JSON codec. *)
202205203203- (** Pretty printer. *)
204206 val pp : Format.formatter -> t -> unit
207207+ (** Pretty printer. *)
205208end
206209207210(** Full PeerTube account details.
208211209209- Contains complete account information including statistics
210210- and the account summary. *)
212212+ Contains complete account information including statistics and the account
213213+ summary. *)
211214module Account : sig
212212- (** Account type. *)
213215 type t
216216+ (** Account type. *)
214217215215- (** Create an account. *)
216218 val make :
217219 summary:Account_summary.t ->
218220 description:string option ->
···221223 following_count:int ->
222224 following_hosts_count:int option ->
223225 t
226226+ (** Create an account. *)
224227225225- (** Basic account information. *)
226228 val summary : t -> Account_summary.t
229229+ (** Basic account information. *)
227230231231+ val description : t -> string option
228232 (** Account description/bio. *)
229229- val description : t -> string option
230233231231- (** Account creation timestamp. *)
232234 val created_at : t -> Ptime.t
235235+ (** Account creation timestamp. *)
233236237237+ val followers_count : t -> int
234238 (** Number of followers. *)
235235- val followers_count : t -> int
236239237237- (** Number of accounts being followed. *)
238240 val following_count : t -> int
241241+ (** Number of accounts being followed. *)
239242240240- (** Number of federated hosts being followed. *)
241243 val following_hosts_count : t -> int option
244244+ (** Number of federated hosts being followed. *)
242245246246+ val jsont : t Jsont.t
243247 (** JSON codec. *)
244244- val jsont : t Jsont.t
245248249249+ val pp : Format.formatter -> t -> unit
246250 (** Pretty printer. *)
247247- val pp : Format.formatter -> t -> unit
248251end
249252250253(** {1 Channel Types} *)
···252255(** Summary of a PeerTube channel.
253256254257 Channel summaries are embedded in other responses (videos, playlists, etc.)
255255- and contain basic identifying information. For full channel details,
256256- use {!Client.get_channel}. *)
258258+ and contain basic identifying information. For full channel details, use
259259+ {!Client.get_channel}. *)
257260module Channel_summary : sig
258258- (** Channel summary type. *)
259261 type t
262262+ (** Channel summary type. *)
260263261261- (** Create a channel summary. *)
262264 val make :
263265 id:int ->
264266 name:string ->
···267269 host:string ->
268270 avatar_path:string option ->
269271 t
272272+ (** Create a channel summary. *)
270273271271- (** Numeric channel ID. *)
272274 val id : t -> int
275275+ (** Numeric channel ID. *)
273276274274- (** Channel name (handle without host). *)
275277 val name : t -> string
278278+ (** Channel name (handle without host). *)
276279277277- (** Human-readable display name. *)
278280 val display_name : t -> string
281281+ (** Human-readable display name. *)
279282283283+ val url : t -> string
280284 (** Full channel URL. *)
281281- val url : t -> string
282285286286+ val host : t -> string
283287 (** Instance host. *)
284284- val host : t -> string
285288286286- (** Avatar image path (relative to instance URL). *)
287289 val avatar_path : t -> string option
290290+ (** Avatar image path (relative to instance URL). *)
288291292292+ val jsont : t Jsont.t
289293 (** JSON codec. *)
290290- val jsont : t Jsont.t
291294295295+ val pp : Format.formatter -> t -> unit
292296 (** Pretty printer. *)
293293- val pp : Format.formatter -> t -> unit
294297end
295298296299(** Full PeerTube channel details.
297300298298- Contains complete channel information including statistics,
299299- the owner account, and the channel summary. *)
301301+ Contains complete channel information including statistics, the owner
302302+ account, and the channel summary. *)
300303module Channel : sig
304304+ type t
301305 (** Channel type. *)
302302- type t
303306304304- (** Create a channel. *)
305307 val make :
306308 summary:Channel_summary.t ->
307309 description:string option ->
···312314 banner_path:string option ->
313315 owner_account:Account_summary.t option ->
314316 t
317317+ (** Create a channel. *)
315318319319+ val summary : t -> Channel_summary.t
316320 (** Basic channel information. *)
317317- val summary : t -> Channel_summary.t
318321319319- (** Channel description. *)
320322 val description : t -> string option
323323+ (** Channel description. *)
321324322322- (** Support text or links (e.g., donation info). *)
323325 val support : t -> string option
326326+ (** Support text or links (e.g., donation info). *)
324327325325- (** Channel creation timestamp. *)
326328 val created_at : t -> Ptime.t
329329+ (** Channel creation timestamp. *)
327330328328- (** Number of followers. *)
329331 val followers_count : t -> int
332332+ (** Number of followers. *)
330333334334+ val following_count : t -> int
331335 (** Number of accounts being followed. *)
332332- val following_count : t -> int
333336337337+ val banner_path : t -> string option
334338 (** Banner image path (relative to instance URL). *)
335335- val banner_path : t -> string option
336339337337- (** Account that owns this channel. *)
338340 val owner_account : t -> Account_summary.t option
341341+ (** Account that owns this channel. *)
339342340340- (** JSON codec. *)
341343 val jsont : t Jsont.t
344344+ (** JSON codec. *)
342345346346+ val pp : Format.formatter -> t -> unit
343347 (** Pretty printer. *)
344344- val pp : Format.formatter -> t -> unit
345348end
346349347350(** {1 Video Types} *)
···351354 Contains all metadata for a video including identifiers, timestamps,
352355 statistics, and references to the channel and account that published it. *)
353356module Video : sig
354354- (** Video type. *)
355357 type t
358358+ (** Video type. *)
356359357357- (** Create a video. *)
358360 val make :
359361 id:int ->
360362 uuid:string ->
···382384 channel:Channel_summary.t option ->
383385 account:Account_summary.t option ->
384386 t
387387+ (** Create a video. *)
385388389389+ val id : t -> int
386390 (** Numeric video ID. *)
387387- val id : t -> int
388391389389- (** Video UUID (standard format). *)
390392 val uuid : t -> string
393393+ (** Video UUID (standard format). *)
391394395395+ val short_uuid : t -> string option
392396 (** Short UUID for compact URLs. *)
393393- val short_uuid : t -> string option
394397395395- (** Video title. *)
396398 val name : t -> string
399399+ (** Video title. *)
397400401401+ val description : t -> string option
398402 (** Video description (may contain markdown). *)
399399- val description : t -> string option
400403401401- (** Full video URL. *)
402404 val url : t -> string
405405+ (** Full video URL. *)
403406404404- (** Embed iframe path. *)
405407 val embed_path : t -> string
408408+ (** Embed iframe path. *)
406409410410+ val published_at : t -> Ptime.t
407411 (** Publication timestamp. *)
408408- val published_at : t -> Ptime.t
409412413413+ val originally_published_at : t -> Ptime.t option
410414 (** Original publication timestamp (for re-uploads). *)
411411- val originally_published_at : t -> Ptime.t option
412415413413- (** Last update timestamp. *)
414416 val updated_at : t -> Ptime.t option
417417+ (** Last update timestamp. *)
415418419419+ val thumbnail_path : t -> string option
416420 (** Thumbnail image path (relative to instance URL). *)
417417- val thumbnail_path : t -> string option
418421422422+ val preview_path : t -> string option
419423 (** Preview image path (relative to instance URL). *)
420420- val preview_path : t -> string option
421424422422- (** Video tags. *)
423425 val tags : t -> string list
426426+ (** Video tags. *)
424427425425- (** Duration in seconds. *)
426428 val duration : t -> int
429429+ (** Duration in seconds. *)
427430428428- (** View count. *)
429431 val views : t -> int
432432+ (** View count. *)
430433431431- (** Like count. *)
432434 val likes : t -> int
435435+ (** Like count. *)
433436437437+ val dislikes : t -> int
434438 (** Dislike count. *)
435435- val dislikes : t -> int
436439440440+ val is_local : t -> bool
437441 (** Whether the video is local to this instance (vs federated). *)
438438- val is_local : t -> bool
439442440440- (** Whether this is a live stream. *)
441443 val is_live : t -> bool
444444+ (** Whether this is a live stream. *)
442445446446+ val privacy : t -> Privacy.t
443447 (** Privacy level. *)
444444- val privacy : t -> Privacy.t
445448449449+ val category : t -> int Labeled.t option
446450 (** Video category (e.g., Music, Education). *)
447447- val category : t -> int Labeled.t option
448451449449- (** Video licence (e.g., Creative Commons). *)
450452 val licence : t -> int Labeled.t option
453453+ (** Video licence (e.g., Creative Commons). *)
451454452452- (** Video language. *)
453455 val language : t -> string Labeled.t option
456456+ (** Video language. *)
454457458458+ val channel : t -> Channel_summary.t option
455459 (** Channel that published the video. *)
456456- val channel : t -> Channel_summary.t option
457460461461+ val account : t -> Account_summary.t option
458462 (** Account that published the video. *)
459459- val account : t -> Account_summary.t option
460463464464+ val jsont : t Jsont.t
461465 (** JSON codec. *)
462462- val jsont : t Jsont.t
463466464464- (** Pretty printer. *)
465467 val pp : Format.formatter -> t -> unit
468468+ (** Pretty printer. *)
466469end
467470468471(** {1 Playlist Types} *)
···483486 - [Private] - Only visible to the owner *)
484487 type t = Public | Unlisted | Private
485488486486- (** [to_int t] converts privacy to its API integer representation. *)
487489 val to_int : t -> int
490490+ (** [to_int t] converts privacy to its API integer representation. *)
488491489489- (** [of_int n] converts an API integer to privacy level. *)
490492 val of_int : int -> t
493493+ (** [of_int n] converts an API integer to privacy level. *)
491494492492- (** JSON codec. *)
493495 val jsont : t Jsont.t
496496+ (** JSON codec. *)
494497495495- (** Pretty printer. *)
496498 val pp : Format.formatter -> t -> unit
499499+ (** Pretty printer. *)
497500 end
498501499502 (** {2 Playlist Type} *)
···505508 - [WatchLater] - Special "Watch Later" playlist *)
506509 type t = Regular | WatchLater
507510511511+ val to_int : t -> int
508512 (** [to_int t] converts type to its API integer representation. *)
509509- val to_int : t -> int
510513511511- (** [of_int n] converts an API integer to playlist type. *)
512514 val of_int : int -> t
515515+ (** [of_int n] converts an API integer to playlist type. *)
513516514514- (** JSON codec. *)
515517 val jsont : t Jsont.t
518518+ (** JSON codec. *)
516519520520+ val pp : Format.formatter -> t -> unit
517521 (** Pretty printer. *)
518518- val pp : Format.formatter -> t -> unit
519522 end
520523521524 (** {2 Playlist Element} *)
522525523526 (** An element in a PeerTube playlist.
524527525525- Playlist elements wrap videos with positioning and optional
526526- timestamp information. *)
528528+ Playlist elements wrap videos with positioning and optional timestamp
529529+ information. *)
527530 module Element : sig
528528- (** Playlist element type. *)
529531 type t
532532+ (** Playlist element type. *)
530533531531- (** Create a playlist element. *)
532534 val make :
533535 id:int ->
534536 position:int ->
···536538 stop_timestamp:int option ->
537539 video:Video.t option ->
538540 t
541541+ (** Create a playlist element. *)
539542540540- (** Element ID. *)
541543 val id : t -> int
544544+ (** Element ID. *)
542545546546+ val position : t -> int
543547 (** Position in playlist (1-indexed). *)
544544- val position : t -> int
545548546546- (** Start timestamp in seconds (for partial playback). *)
547549 val start_timestamp : t -> int option
550550+ (** Start timestamp in seconds (for partial playback). *)
548551549549- (** Stop timestamp in seconds (for partial playback). *)
550552 val stop_timestamp : t -> int option
553553+ (** Stop timestamp in seconds (for partial playback). *)
551554555555+ val video : t -> Video.t option
552556 (** The video (may be [None] if video was deleted). *)
553553- val video : t -> Video.t option
554557555555- (** JSON codec. *)
556558 val jsont : t Jsont.t
559559+ (** JSON codec. *)
557560558558- (** Pretty printer. *)
559561 val pp : Format.formatter -> t -> unit
562562+ (** Pretty printer. *)
560563 end
561564562565 (** {2 Playlist} *)
563566564564- (** Playlist type. *)
565567 type t
568568+ (** Playlist type. *)
566569567567- (** Create a playlist. *)
568570 val make :
569571 id:int ->
570572 uuid:string ->
···581583 owner_account:Account_summary.t option ->
582584 video_channel:Channel_summary.t option ->
583585 t
586586+ (** Create a playlist. *)
584587585585- (** Numeric playlist ID. *)
586588 val id : t -> int
589589+ (** Numeric playlist ID. *)
587590588588- (** Playlist UUID. *)
589591 val uuid : t -> string
592592+ (** Playlist UUID. *)
590593591591- (** Short UUID for compact URLs. *)
592594 val short_uuid : t -> string option
595595+ (** Short UUID for compact URLs. *)
593596594594- (** Display name. *)
595597 val display_name : t -> string
598598+ (** Display name. *)
596599600600+ val description : t -> string option
597601 (** Playlist description. *)
598598- val description : t -> string option
599602600600- (** Privacy level. *)
601603 val privacy : t -> Privacy.t
604604+ (** Privacy level. *)
602605603603- (** Full playlist URL. *)
604606 val url : t -> string
607607+ (** Full playlist URL. *)
605608606606- (** Thumbnail image path (relative to instance URL). *)
607609 val thumbnail_path : t -> string option
610610+ (** Thumbnail image path (relative to instance URL). *)
608611609609- (** Number of videos in playlist. *)
610612 val videos_length : t -> int
613613+ (** Number of videos in playlist. *)
611614615615+ val playlist_type : t -> Type.t
612616 (** Playlist type (regular or watch later). *)
613613- val playlist_type : t -> Type.t
614617615615- (** Creation timestamp. *)
616618 val created_at : t -> Ptime.t
619619+ (** Creation timestamp. *)
617620621621+ val updated_at : t -> Ptime.t
618622 (** Last update timestamp. *)
619619- val updated_at : t -> Ptime.t
620623621621- (** Account that owns this playlist. *)
622624 val owner_account : t -> Account_summary.t option
625625+ (** Account that owns this playlist. *)
623626624624- (** Associated video channel (if any). *)
625627 val video_channel : t -> Channel_summary.t option
628628+ (** Associated video channel (if any). *)
626629630630+ val jsont : t Jsont.t
627631 (** JSON codec. *)
628628- val jsont : t Jsont.t
629632633633+ val pp : Format.formatter -> t -> unit
630634 (** Pretty printer. *)
631631- val pp : Format.formatter -> t -> unit
632635end
633636634637(** {1 Server Types} *)
···637640638641 Contains the instance name, description, and basic configuration. *)
639642module Instance_info : sig
640640- (** Instance info type. *)
641643 type t
644644+ (** Instance info type. *)
642645643643- (** Create instance info. *)
644646 val make :
645647 name:string ->
646648 short_description:string ->
···650652 default_nsfw_policy:string ->
651653 default_client_route:string ->
652654 t
655655+ (** Create instance info. *)
653656657657+ val name : t -> string
654658 (** Instance name. *)
655655- val name : t -> string
656659657657- (** Short description (one line). *)
658660 val short_description : t -> string
661661+ (** Short description (one line). *)
659662660660- (** Full description (may contain markdown). *)
661663 val description : t -> string option
664664+ (** Full description (may contain markdown). *)
662665663663- (** Terms of service. *)
664666 val terms : t -> string option
667667+ (** Terms of service. *)
665668666666- (** Whether the instance is NSFW-focused. *)
667669 val is_nsfw : t -> bool
670670+ (** Whether the instance is NSFW-focused. *)
668671672672+ val default_nsfw_policy : t -> string
669673 (** Default NSFW display policy ("display", "blur", "do_not_list"). *)
670670- val default_nsfw_policy : t -> string
671674675675+ val default_client_route : t -> string
672676 (** Default client route (e.g., "/videos/trending"). *)
673673- val default_client_route : t -> string
674677675675- (** JSON codec. *)
676678 val jsont : t Jsont.t
679679+ (** JSON codec. *)
677680678678- (** Pretty printer. *)
679681 val pp : Format.formatter -> t -> unit
682682+ (** Pretty printer. *)
680683end
681684682685(** PeerTube server configuration.
683686684687 Contains server version, enabled features, and instance information. *)
685688module Server_config : sig
686686- (** Server config type. *)
687689 type t
690690+ (** Server config type. *)
688691689689- (** Create server config. *)
690692 val make :
691693 instance:Instance_info.t ->
692694 server_version:string ->
···697699 transcoding_enabled:bool ->
698700 contact_form_enabled:bool ->
699701 t
702702+ (** Create server config. *)
700703701701- (** Instance information. *)
702704 val instance : t -> Instance_info.t
705705+ (** Instance information. *)
703706707707+ val server_version : t -> string
704708 (** PeerTube server version (e.g., "5.2.0"). *)
705705- val server_version : t -> string
706709710710+ val server_commit : t -> string option
707711 (** Git commit hash (if available). *)
708708- val server_commit : t -> string option
709712713713+ val signup_allowed : t -> bool
710714 (** Whether new user signup is allowed. *)
711711- val signup_allowed : t -> bool
712715713713- (** Whether signup is allowed for the current IP address. *)
714716 val signup_allowed_for_current_ip : t -> bool
717717+ (** Whether signup is allowed for the current IP address. *)
715718716716- (** Whether signup requires email verification. *)
717719 val signup_requires_email_verification : t -> bool
720720+ (** Whether signup requires email verification. *)
718721719719- (** Whether video transcoding is enabled. *)
720722 val transcoding_enabled : t -> bool
723723+ (** Whether video transcoding is enabled. *)
721724722722- (** Whether the contact form is enabled. *)
723725 val contact_form_enabled : t -> bool
726726+ (** Whether the contact form is enabled. *)
724727728728+ val jsont : t Jsont.t
725729 (** JSON codec. *)
726726- val jsont : t Jsont.t
727730731731+ val pp : Format.formatter -> t -> unit
728732 (** Pretty printer. *)
729729- val pp : Format.formatter -> t -> unit
730733end
731734732735(** PeerTube server statistics.
733736734734- Contains usage statistics for the instance including user counts,
735735- video counts, and federation information. *)
737737+ Contains usage statistics for the instance including user counts, video
738738+ counts, and federation information. *)
736739module Server_stats : sig
737737- (** Server stats type. *)
738740 type t
741741+ (** Server stats type. *)
739742740740- (** Create server stats. *)
741743 val make :
742744 total_users:int ->
743745 total_daily_active_users:int ->
···754756 total_instance_followers:int ->
755757 total_instance_following:int ->
756758 t
759759+ (** Create server stats. *)
757760761761+ val total_users : t -> int
758762 (** Total registered users. *)
759759- val total_users : t -> int
760763761761- (** Users active in the last day. *)
762764 val total_daily_active_users : t -> int
765765+ (** Users active in the last day. *)
763766764764- (** Users active in the last week. *)
765767 val total_weekly_active_users : t -> int
768768+ (** Users active in the last week. *)
766769770770+ val total_monthly_active_users : t -> int
767771 (** Users active in the last month. *)
768768- val total_monthly_active_users : t -> int
769772770770- (** Videos hosted on this instance. *)
771773 val total_local_videos : t -> int
774774+ (** Videos hosted on this instance. *)
772775776776+ val total_local_video_views : t -> int
773777 (** Total views on local videos. *)
774774- val total_local_video_views : t -> int
775778776776- (** Total comments on local videos. *)
777779 val total_local_video_comments : t -> int
780780+ (** Total comments on local videos. *)
778781779779- (** Total size of local video files in bytes. *)
780782 val total_local_video_files_size : t -> int64
783783+ (** Total size of local video files in bytes. *)
781784785785+ val total_videos : t -> int
782786 (** Total videos including federated content. *)
783783- val total_videos : t -> int
784787788788+ val total_video_comments : t -> int
785789 (** Total comments including federated content. *)
786786- val total_video_comments : t -> int
787790788788- (** Video channels on this instance. *)
789791 val total_local_video_channels : t -> int
792792+ (** Video channels on this instance. *)
790793794794+ val total_local_playlists : t -> int
791795 (** Playlists on this instance. *)
792792- val total_local_playlists : t -> int
793796797797+ val total_instance_followers : t -> int
794798 (** Instances following this instance. *)
795795- val total_instance_followers : t -> int
796799797797- (** Instances this instance follows. *)
798800 val total_instance_following : t -> int
801801+ (** Instances this instance follows. *)
799802800800- (** JSON codec. *)
801803 val jsont : t Jsont.t
804804+ (** JSON codec. *)
802805803803- (** Pretty printer. *)
804806 val pp : Format.formatter -> t -> unit
807807+ (** Pretty printer. *)
805808end
806809807810(** {1 API Client} *)
···819822module Client : sig
820823 (** {2 Session} *)
821824825825+ type t
822826 (** A PeerTube API session.
823827824824- Encapsulates the HTTP client and base URL for making API requests.
825825- In future, this may also contain authentication credentials. *)
826826- type t
828828+ Encapsulates the HTTP client and base URL for making API requests. In
829829+ future, this may also contain authentication credentials. *)
827830831831+ val create : session:Requests.t -> base_url:string -> t
828832 (** [create ~session ~base_url] creates a new PeerTube API session.
829833830834 @param session HTTP client session from the Requests library
831831- @param base_url Base URL of the PeerTube instance (e.g., "https://framatube.org") *)
832832- val create : session:Requests.t -> base_url:string -> t
835835+ @param base_url
836836+ Base URL of the PeerTube instance (e.g., "https://framatube.org") *)
833837838838+ val base_url : t -> string
834839 (** [base_url t] returns the base URL of the PeerTube instance. *)
835835- val base_url : t -> string
836840837837- (** [http_session t] returns the underlying HTTP session. *)
838841 val http_session : t -> Requests.t
842842+ (** [http_session t] returns the underlying HTTP session. *)
839843840844 (** {2 Errors} *)
841845842842- (** Log source for debug/info messages. *)
843846 val log_src : Logs.src
847847+ (** Log source for debug/info messages. *)
844848845845- (** API error with HTTP status code and message.
846846- Raised when the server returns an error response. *)
847849 exception Api_error of int * string
850850+ (** API error with HTTP status code and message. Raised when the server
851851+ returns an error response. *)
848852849853 (** {2 Video Operations} *)
850854855855+ val list_videos :
856856+ t ->
857857+ ?count:int ->
858858+ ?start:int ->
859859+ ?sort:Video_sort.t ->
860860+ ?nsfw:bool ->
861861+ ?is_local:bool ->
862862+ ?is_live:bool ->
863863+ ?category_id:int ->
864864+ ?tags:string ->
865865+ unit ->
866866+ Video.t Paginated.t
851867 (** List videos with optional filtering and sorting.
852868853869 @param count Number of videos per page (default: 20)
···858874 @param is_live Only live streams
859875 @param category_id Filter by category ID
860876 @param tags Filter by tags (comma-separated) *)
861861- val list_videos :
877877+878878+ val search_videos :
862879 t ->
880880+ query:string ->
863881 ?count:int ->
864882 ?start:int ->
865883 ?sort:Video_sort.t ->
866866- ?nsfw:bool ->
867867- ?is_local:bool ->
868868- ?is_live:bool ->
869869- ?category_id:int ->
870870- ?tags:string ->
884884+ ?search_target:[ `Local | `Search_index ] ->
885885+ ?duration_min:int ->
886886+ ?duration_max:int ->
887887+ ?published_after:Ptime.t ->
888888+ ?published_before:Ptime.t ->
871889 unit ->
872890 Video.t Paginated.t
873873-874891 (** Search for videos.
875892876893 @param query Search query string
877894 @param count Number of results per page (default: 20)
878895 @param start Starting offset (default: 0)
879896 @param sort Sort order (default: {!Video_sort.Best})
880880- @param search_target [`Local] for this instance, [`Search_index] for federated search
897897+ @param search_target
898898+ [`Local] for this instance, [`Search_index] for federated search
881899 @param duration_min Minimum duration in seconds
882900 @param duration_max Maximum duration in seconds
883901 @param published_after Only videos published after this date
884902 @param published_before Only videos published before this date *)
885885- val search_videos :
903903+904904+ val fetch_channel_videos :
886905 t ->
887887- query:string ->
888906 ?count:int ->
889907 ?start:int ->
890890- ?sort:Video_sort.t ->
891891- ?search_target:[ `Local | `Search_index ] ->
892892- ?duration_min:int ->
893893- ?duration_max:int ->
894894- ?published_after:Ptime.t ->
895895- ?published_before:Ptime.t ->
908908+ channel:string ->
896909 unit ->
897910 Video.t Paginated.t
898898-899911 (** Fetch videos from a channel with pagination.
900912901913 @param channel Channel name (e.g., "my_channel") *)
902902- val fetch_channel_videos :
903903- t -> ?count:int -> ?start:int -> channel:string -> unit -> Video.t Paginated.t
904914915915+ val fetch_all_channel_videos :
916916+ t ->
917917+ ?page_size:int ->
918918+ ?max_pages:int ->
919919+ channel:string ->
920920+ unit ->
921921+ Video.t list
905922 (** Fetch all videos from a channel using automatic pagination.
906923907907- Repeatedly fetches pages until all videos are retrieved or
908908- [max_pages] is reached.
924924+ Repeatedly fetches pages until all videos are retrieved or [max_pages] is
925925+ reached.
909926910927 @param page_size Videos per page (default: 20)
911928 @param max_pages Maximum pages to fetch (default: unlimited) *)
912912- val fetch_all_channel_videos :
913913- t -> ?page_size:int -> ?max_pages:int -> channel:string -> unit -> Video.t list
914929930930+ val fetch_video_details : t -> uuid:string -> unit -> Video.t
915931 (** Fetch detailed information for a single video.
916932917933 @param uuid Video UUID *)
918918- val fetch_video_details : t -> uuid:string -> unit -> Video.t
919934935935+ val get_categories : t -> unit -> (int * string) list
920936 (** Get available video categories.
921937922938 Returns a list of [(id, label)] pairs. *)
923923- val get_categories : t -> unit -> (int * string) list
924939940940+ val get_licences : t -> unit -> (int * string) list
925941 (** Get available video licences.
926942927943 Returns a list of [(id, label)] pairs. *)
928928- val get_licences : t -> unit -> (int * string) list
929944945945+ val get_languages : t -> unit -> (string * string) list
930946 (** Get available video languages.
931947932948 Returns a list of [(code, label)] pairs. *)
933933- val get_languages : t -> unit -> (string * string) list
934949935950 (** {2 Channel Operations} *)
936951952952+ val list_channels :
953953+ t ->
954954+ ?count:int ->
955955+ ?start:int ->
956956+ ?sort:string ->
957957+ unit ->
958958+ Channel.t Paginated.t
937959 (** List all channels on the instance.
938960939961 @param sort Sort order (e.g., "-createdAt" for newest first) *)
940940- val list_channels :
941941- t -> ?count:int -> ?start:int -> ?sort:string -> unit -> Channel.t Paginated.t
942962963963+ val search_channels :
964964+ t ->
965965+ query:string ->
966966+ ?count:int ->
967967+ ?start:int ->
968968+ unit ->
969969+ Channel.t Paginated.t
943970 (** Search for channels.
944971945972 @param query Search query string *)
946946- val search_channels :
947947- t -> query:string -> ?count:int -> ?start:int -> unit -> Channel.t Paginated.t
948973974974+ val get_channel : t -> handle:string -> unit -> Channel.t
949975 (** Get details for a specific channel.
950976951951- @param handle Channel handle (e.g., "my_channel" or "my_channel\@example.com") *)
952952- val get_channel : t -> handle:string -> unit -> Channel.t
977977+ @param handle
978978+ Channel handle (e.g., "my_channel" or "my_channel@example.com") *)
953979954980 (** {2 Account Operations} *)
955981982982+ val list_accounts :
983983+ t ->
984984+ ?count:int ->
985985+ ?start:int ->
986986+ ?sort:string ->
987987+ unit ->
988988+ Account.t Paginated.t
956989 (** List accounts on the instance.
957990958991 @param sort Sort order (e.g., "-createdAt" for newest first) *)
959959- val list_accounts :
960960- t -> ?count:int -> ?start:int -> ?sort:string -> unit -> Account.t Paginated.t
961992993993+ val get_account : t -> handle:string -> unit -> Account.t
962994 (** Get details for a specific account.
963995964964- @param handle Account handle (e.g., "username" or "username\@example.com") *)
965965- val get_account : t -> handle:string -> unit -> Account.t
996996+ @param handle Account handle (e.g., "username" or "username@example.com")
997997+ *)
966998999999+ val get_account_videos :
10001000+ t ->
10011001+ ?count:int ->
10021002+ ?start:int ->
10031003+ handle:string ->
10041004+ unit ->
10051005+ Video.t Paginated.t
9671006 (** Get videos from a specific account. *)
968968- val get_account_videos :
969969- t -> ?count:int -> ?start:int -> handle:string -> unit -> Video.t Paginated.t
970100710081008+ val get_account_channels :
10091009+ t ->
10101010+ ?count:int ->
10111011+ ?start:int ->
10121012+ handle:string ->
10131013+ unit ->
10141014+ Channel.t Paginated.t
9711015 (** Get channels owned by an account. *)
972972- val get_account_channels :
973973- t -> ?count:int -> ?start:int -> handle:string -> unit -> Channel.t Paginated.t
97410169751017 (** {2 Playlist Operations} *)
976101810191019+ val list_playlists :
10201020+ t -> ?count:int -> ?start:int -> unit -> Playlist.t Paginated.t
9771021 (** List playlists on the instance. *)
978978- val list_playlists : t -> ?count:int -> ?start:int -> unit -> Playlist.t Paginated.t
979102210231023+ val search_playlists :
10241024+ t ->
10251025+ query:string ->
10261026+ ?count:int ->
10271027+ ?start:int ->
10281028+ unit ->
10291029+ Playlist.t Paginated.t
9801030 (** Search for playlists.
98110319821032 @param query Search query string *)
983983- val search_playlists :
984984- t -> query:string -> ?count:int -> ?start:int -> unit -> Playlist.t Paginated.t
985103310341034+ val get_playlist : t -> id:string -> unit -> Playlist.t
9861035 (** Get details for a specific playlist.
98710369881037 @param id Playlist ID or UUID *)
989989- val get_playlist : t -> id:string -> unit -> Playlist.t
990103810391039+ val get_playlist_videos :
10401040+ t ->
10411041+ ?count:int ->
10421042+ ?start:int ->
10431043+ id:string ->
10441044+ unit ->
10451045+ Playlist.Element.t Paginated.t
9911046 (** Get videos in a playlist.
99210479931048 @param id Playlist ID or UUID *)
994994- val get_playlist_videos :
995995- t -> ?count:int -> ?start:int -> id:string -> unit -> Playlist.Element.t Paginated.t
9961049997997- (** Get playlists owned by an account. *)
9981050 val get_account_playlists :
999999- t -> ?count:int -> ?start:int -> handle:string -> unit -> Playlist.t Paginated.t
10511051+ t ->
10521052+ ?count:int ->
10531053+ ?start:int ->
10541054+ handle:string ->
10551055+ unit ->
10561056+ Playlist.t Paginated.t
10571057+ (** Get playlists owned by an account. *)
1000105810011059 (** {2 Server Operations} *)
1002106010031003- (** Get server configuration. *)
10041061 val get_config : t -> unit -> Server_config.t
10621062+ (** Get server configuration. *)
1005106310061006- (** Get server statistics. *)
10071064 val get_stats : t -> unit -> Server_stats.t
10651065+ (** Get server statistics. *)
1008106610091067 (** {2 Utilities} *)
1010106810691069+ val thumbnail_url : t -> Video.t -> string option
10111070 (** Get the full thumbnail URL for a video.
1012107110131013- Combines the session's base URL with the video's thumbnail path.
10141014- Returns [None] if the video has no thumbnail. *)
10151015- val thumbnail_url : t -> Video.t -> string option
10721072+ Combines the session's base URL with the video's thumbnail path. Returns
10731073+ [None] if the video has no thumbnail. *)
1016107410751075+ val download_thumbnail :
10761076+ t ->
10771077+ video:Video.t ->
10781078+ output_path:string ->
10791079+ unit ->
10801080+ (unit, [ `Msg of string ]) result
10171081 (** Download a video's thumbnail to a file.
1018108210191083 @param output_path Path to save the thumbnail image *)
10201020- val download_thumbnail :
10211021- t -> video:Video.t -> output_path:string -> unit -> (unit, [ `Msg of string ]) result
1022108410851085+ val to_tuple : Video.t -> string * Ptime.t * string * string * string * string
10231086 (** Convert a video to a tuple for external use.
1024108710251088 Returns [(description, published_date, title, url, uuid, id_string)]. *)
10261026- val to_tuple : Video.t -> string * Ptime.t * string * string * string * string
10271089end
···11(** Full PeerTube account details. *)
2233-(** Account type. *)
43type t
44+(** Account type. *)
5566-(** Create an account. *)
76val make :
87 summary:Peertube_account_summary.t ->
98 description:string option ->
···1211 following_count:int ->
1312 following_hosts_count:int option ->
1413 t
1414+(** Create an account. *)
15151616-(** Account summary (basic info). *)
1716val summary : t -> Peertube_account_summary.t
1717+(** Account summary (basic info). *)
18181919+val description : t -> string option
1920(** Account description/bio. *)
2020-val description : t -> string option
21212222-(** Account creation timestamp. *)
2322val created_at : t -> Ptime.t
2323+(** Account creation timestamp. *)
24242525-(** Number of followers. *)
2625val followers_count : t -> int
2626+(** Number of followers. *)
27272828+val following_count : t -> int
2829(** Number of accounts being followed. *)
2929-val following_count : t -> int
30303131-(** Number of hosts being followed (federation). *)
3231val following_hosts_count : t -> int option
3232+(** Number of hosts being followed (federation). *)
33333434+val jsont : t Jsont.t
3435(** JSON codec. *)
3535-val jsont : t Jsont.t
36363737-(** Pretty printer. *)
3837val pp : Format.formatter -> t -> unit
3838+(** Pretty printer. *)
···11(** Avatar path extraction from PeerTube API responses.
2233- PeerTube returns avatars as an array of objects with path and width.
44- This module extracts the first avatar path. *)
33+ PeerTube returns avatars as an array of objects with path and width. This
44+ module extracts the first avatar path. *)
5566+val jsont : string option Jsont.t
67(** JSON codec that extracts the first avatar path from an avatars array. *)
77-val jsont : string option Jsont.t
···11(** Summary of a PeerTube channel (embedded in other responses). *)
2233-(** Channel summary type. *)
43type t
44+(** Channel summary type. *)
5566-(** Create a channel summary. *)
76val make :
87 id:int ->
98 name:string ->
···1211 host:string ->
1312 avatar_path:string option ->
1413 t
1414+(** Create a channel summary. *)
15151616-(** Channel ID. *)
1716val id : t -> int
1717+(** Channel ID. *)
18181919+val name : t -> string
1920(** Channel name (handle without host). *)
2020-val name : t -> string
21212222-(** Display name. *)
2322val display_name : t -> string
2323+(** Display name. *)
24242525-(** Channel URL. *)
2625val url : t -> string
2626+(** Channel URL. *)
27272828+val host : t -> string
2829(** Instance host. *)
2929-val host : t -> string
30303131-(** Avatar image path (relative). *)
3231val avatar_path : t -> string option
3232+(** Avatar image path (relative). *)
33333434+val jsont : t Jsont.t
3435(** JSON codec. *)
3535-val jsont : t Jsont.t
36363737-(** Pretty printer. *)
3837val pp : Format.formatter -> t -> unit
3838+(** Pretty printer. *)
+76-53
lib/peertube_client.ml
···11(** PeerTube API client functions. *)
2233-(** Session type encapsulating HTTP client and base URL. *)
43type t = { session : Requests.t; base_url : string }
44+(** Session type encapsulating HTTP client and base URL. *)
5566let create ~session ~base_url = { session; base_url }
77let base_url t = t.base_url
88let http_session t = t.session
99-109let log_src = Logs.Src.create "peertube" ~doc:"PeerTube API client"
11101211module Log = (val Logs.src_log log_src : Logs.LOG)
···2322 in
2423 Jsont.Object.map ~kind:"error_response" make
2524 |> Jsont.Object.mem "type" Jsont.string ~dec_absent:"" ~enc:(Fun.const "")
2626- |> Jsont.Object.mem "error" (Jsont.option Jsont.string) ~dec_absent:None
2727- ~enc_omit:Option.is_none ~enc:(Fun.const None)
2525+ |> Jsont.Object.mem "error"
2626+ (Jsont.option Jsont.string)
2727+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:(Fun.const None)
2828 |> Jsont.Object.mem "status" Jsont.int ~dec_absent:0 ~enc:(Fun.const 0)
2929- |> Jsont.Object.mem "detail" (Jsont.option Jsont.string) ~dec_absent:None
3030- ~enc_omit:Option.is_none ~enc:Option.some
3131- |> Jsont.Object.skip_unknown
3232- |> Jsont.Object.finish
2929+ |> Jsont.Object.mem "detail"
3030+ (Jsont.option Jsont.string)
3131+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:Option.some
3232+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
33333434let raise_api_error status body =
3535 let msg =
···7474let video_paginated_jsont =
7575 Peertube_paginated.jsont ~kind:"video_paginated" Peertube_video.jsont
76767777-let list_videos t ?(count = 20) ?(start = 0) ?(sort = Peertube_video_sort.Newest)
7878- ?(nsfw = false) ?is_local ?is_live ?category_id ?tags () =
7777+let list_videos t ?(count = 20) ?(start = 0)
7878+ ?(sort = Peertube_video_sort.Newest) ?(nsfw = false) ?is_local ?is_live
7979+ ?category_id ?tags () =
7980 let url =
8081 build_url t.base_url [ "api"; "v1"; "videos" ]
8182 [
···8384 Some ("start", string_of_int start);
8485 Some ("sort", Peertube_video_sort.to_string sort);
8586 Some ("nsfw", if nsfw then "true" else "false");
8686- Option.map (fun b -> ("isLocal", if b then "true" else "false")) is_local;
8787+ Option.map
8888+ (fun b -> ("isLocal", if b then "true" else "false"))
8989+ is_local;
8790 Option.map (fun b -> ("isLive", if b then "true" else "false")) is_live;
8891 Option.map (fun i -> ("categoryOneOf", string_of_int i)) category_id;
8992 Option.map (fun t -> ("tagsOneOf", t)) tags;
···100103 ?(sort = Peertube_video_sort.Best) ?(search_target = `Local) ?duration_min
101104 ?duration_max ?published_after ?published_before () =
102105 let url =
103103- build_url t.base_url [ "api"; "v1"; "search"; "videos" ]
106106+ build_url t.base_url
107107+ [ "api"; "v1"; "search"; "videos" ]
104108 [
105109 Some ("search", query);
106110 Some ("count", string_of_int count);
···126130127131let fetch_channel_videos t ?(count = 20) ?(start = 0) ~channel () =
128132 let url =
129129- build_url t.base_url [ "api"; "v1"; "video-channels"; channel; "videos" ]
133133+ build_url t.base_url
134134+ [ "api"; "v1"; "video-channels"; channel; "videos" ]
130135 [
131131- Some ("count", string_of_int count);
132132- Some ("start", string_of_int start);
136136+ Some ("count", string_of_int count); Some ("start", string_of_int start);
133137 ]
134138 in
135139 let result = get_json ~session:t.session ~url video_paginated_jsont in
136140 Log.info (fun m ->
137141 m "Fetched %d videos from channel %s (total: %d)"
138142 (List.length (Peertube_paginated.data result))
139139- channel (Peertube_paginated.total result));
143143+ channel
144144+ (Peertube_paginated.total result));
140145 result
141146142147let fetch_all_channel_videos t ?(page_size = 20) ?max_pages ~channel () =
···147152 let rec fetch_pages page start acc =
148153 let response = fetch_channel_videos t ~count:page_size ~start ~channel () in
149154 let all_videos = acc @ Peertube_paginated.data response in
150150- let fetched_count = start + List.length (Peertube_paginated.data response) in
155155+ let fetched_count =
156156+ start + List.length (Peertube_paginated.data response)
157157+ in
151158 let more_available = fetched_count < Peertube_paginated.total response in
152159 let under_max_pages =
153160 match max_pages with None -> true | Some max -> page < max
···155162 Log.debug (fun m ->
156163 m "Page %d: fetched %d, total so far %d/%d" page
157164 (List.length (Peertube_paginated.data response))
158158- fetched_count (Peertube_paginated.total response));
165165+ fetched_count
166166+ (Peertube_paginated.total response));
159167 if more_available && under_max_pages then
160168 fetch_pages (page + 1) fetched_count all_videos
161169 else begin
···225233226234let list_channels t ?(count = 20) ?(start = 0) ?(sort = "-createdAt") () =
227235 let url =
228228- build_url t.base_url [ "api"; "v1"; "video-channels" ]
236236+ build_url t.base_url
237237+ [ "api"; "v1"; "video-channels" ]
229238 [
230239 Some ("count", string_of_int count);
231240 Some ("start", string_of_int start);
···241250242251let search_channels t ~query ?(count = 20) ?(start = 0) () =
243252 let url =
244244- build_url t.base_url [ "api"; "v1"; "search"; "video-channels" ]
253253+ build_url t.base_url
254254+ [ "api"; "v1"; "search"; "video-channels" ]
245255 [
246256 Some ("search", query);
247257 Some ("count", string_of_int count);
···260270 let channel = get_json ~session:t.session ~url Peertube_channel.jsont in
261271 Log.info (fun m ->
262272 m "Fetched channel: %s"
263263- (Peertube_channel_summary.display_name (Peertube_channel.summary channel)));
273273+ (Peertube_channel_summary.display_name
274274+ (Peertube_channel.summary channel)));
264275 channel
265276266277(* Account operations *)
···270281271282let list_accounts t ?(count = 20) ?(start = 0) ?(sort = "-createdAt") () =
272283 let url =
273273- build_url t.base_url [ "api"; "v1"; "accounts" ]
284284+ build_url t.base_url
285285+ [ "api"; "v1"; "accounts" ]
274286 [
275287 Some ("count", string_of_int count);
276288 Some ("start", string_of_int start);
···289301 let account = get_json ~session:t.session ~url Peertube_account.jsont in
290302 Log.info (fun m ->
291303 m "Fetched account: %s"
292292- (Peertube_account_summary.display_name (Peertube_account.summary account)));
304304+ (Peertube_account_summary.display_name
305305+ (Peertube_account.summary account)));
293306 account
294307295308let get_account_videos t ?(count = 20) ?(start = 0) ~handle () =
296309 let url =
297297- build_url t.base_url [ "api"; "v1"; "accounts"; handle; "videos" ]
310310+ build_url t.base_url
311311+ [ "api"; "v1"; "accounts"; handle; "videos" ]
298312 [
299299- Some ("count", string_of_int count);
300300- Some ("start", string_of_int start);
313313+ Some ("count", string_of_int count); Some ("start", string_of_int start);
301314 ]
302315 in
303316 let result = get_json ~session:t.session ~url video_paginated_jsont in
304317 Log.info (fun m ->
305318 m "Fetched %d videos from account %s (total: %d)"
306319 (List.length (Peertube_paginated.data result))
307307- handle (Peertube_paginated.total result));
320320+ handle
321321+ (Peertube_paginated.total result));
308322 result
309323310324let get_account_channels t ?(count = 20) ?(start = 0) ~handle () =
311325 let url =
312312- build_url t.base_url [ "api"; "v1"; "accounts"; handle; "video-channels" ]
326326+ build_url t.base_url
327327+ [ "api"; "v1"; "accounts"; handle; "video-channels" ]
313328 [
314314- Some ("count", string_of_int count);
315315- Some ("start", string_of_int start);
329329+ Some ("count", string_of_int count); Some ("start", string_of_int start);
316330 ]
317331 in
318332 let result = get_json ~session:t.session ~url channel_paginated_jsont in
319333 Log.info (fun m ->
320334 m "Fetched %d channels from account %s (total: %d)"
321335 (List.length (Peertube_paginated.data result))
322322- handle (Peertube_paginated.total result));
336336+ handle
337337+ (Peertube_paginated.total result));
323338 result
324339325340(* Playlist operations *)
···333348334349let list_playlists t ?(count = 20) ?(start = 0) () =
335350 let url =
336336- build_url t.base_url [ "api"; "v1"; "video-playlists" ]
351351+ build_url t.base_url
352352+ [ "api"; "v1"; "video-playlists" ]
337353 [
338338- Some ("count", string_of_int count);
339339- Some ("start", string_of_int start);
354354+ Some ("count", string_of_int count); Some ("start", string_of_int start);
340355 ]
341356 in
342357 let result = get_json ~session:t.session ~url playlist_paginated_jsont in
···348363349364let search_playlists t ~query ?(count = 20) ?(start = 0) () =
350365 let url =
351351- build_url t.base_url [ "api"; "v1"; "search"; "video-playlists" ]
366366+ build_url t.base_url
367367+ [ "api"; "v1"; "search"; "video-playlists" ]
352368 [
353369 Some ("search", query);
354370 Some ("count", string_of_int count);
···371387372388let get_playlist_videos t ?(count = 20) ?(start = 0) ~id () =
373389 let url =
374374- build_url t.base_url [ "api"; "v1"; "video-playlists"; id; "videos" ]
390390+ build_url t.base_url
391391+ [ "api"; "v1"; "video-playlists"; id; "videos" ]
375392 [
376376- Some ("count", string_of_int count);
377377- Some ("start", string_of_int start);
393393+ Some ("count", string_of_int count); Some ("start", string_of_int start);
378394 ]
379395 in
380380- let result = get_json ~session:t.session ~url playlist_element_paginated_jsont in
396396+ let result =
397397+ get_json ~session:t.session ~url playlist_element_paginated_jsont
398398+ in
381399 Log.info (fun m ->
382400 m "Fetched %d videos from playlist (total: %d)"
383401 (List.length (Peertube_paginated.data result))
···386404387405let get_account_playlists t ?(count = 20) ?(start = 0) ~handle () =
388406 let url =
389389- build_url t.base_url [ "api"; "v1"; "accounts"; handle; "video-playlists" ]
407407+ build_url t.base_url
408408+ [ "api"; "v1"; "accounts"; handle; "video-playlists" ]
390409 [
391391- Some ("count", string_of_int count);
392392- Some ("start", string_of_int start);
410410+ Some ("count", string_of_int count); Some ("start", string_of_int start);
393411 ]
394412 in
395413 let result = get_json ~session:t.session ~url playlist_paginated_jsont in
396414 Log.info (fun m ->
397415 m "Fetched %d playlists from account %s (total: %d)"
398416 (List.length (Peertube_paginated.data result))
399399- handle (Peertube_paginated.total result));
417417+ handle
418418+ (Peertube_paginated.total result));
400419 result
401420402421(* Server operations *)
···422441(* Utilities *)
423442424443let thumbnail_url t video =
425425- match Peertube_video.thumbnail_path video with
426426- | Some path -> Some (t.base_url ^ path)
427427- | None -> None
444444+ Option.map
445445+ (fun path -> t.base_url ^ path)
446446+ (Peertube_video.thumbnail_path video)
428447429448let download_thumbnail t ~video ~output_path () =
430449 match thumbnail_url t video with
···433452 m "No thumbnail available for video %s" (Peertube_video.uuid video));
434453 Error
435454 (`Msg
436436- (Printf.sprintf "No thumbnail available for video %s"
437437- (Peertube_video.uuid video)))
455455+ (Printf.sprintf "No thumbnail available for video %s"
456456+ (Peertube_video.uuid video)))
438457 | Some url ->
439458 Log.debug (fun m -> m "Downloading thumbnail from %s" url);
440459 let response = Requests.get t.session url in
···446465 output_string oc body;
447466 close_out oc;
448467 Log.info (fun m ->
449449- m "Downloaded thumbnail for %s to %s" (Peertube_video.uuid video)
468468+ m "Downloaded thumbnail for %s to %s"
469469+ (Peertube_video.uuid video)
450470 output_path);
451471 Ok ()
452472 with exn ->
···455475 (Printexc.to_string exn));
456476 Error
457477 (`Msg
458458- (Printf.sprintf "Failed to write thumbnail: %s"
459459- (Printexc.to_string exn)))
478478+ (Printf.sprintf "Failed to write thumbnail: %s"
479479+ (Printexc.to_string exn)))
460480 end
461481 else begin
462482 Log.err (fun m ->
···466486 end
467487468488let to_tuple video =
469469- let description = Option.value ~default:"" (Peertube_video.description video) in
489489+ let description =
490490+ Option.value ~default:"" (Peertube_video.description video)
491491+ in
470492 let published_date =
471471- Option.value ~default:(Peertube_video.published_at video)
493493+ Option.value
494494+ ~default:(Peertube_video.published_at video)
472495 (Peertube_video.originally_published_at video)
473496 in
474497 ( description,
+66-60
lib/peertube_client.mli
···11(** PeerTube API client functions.
2233- This module provides functions for interacting with the PeerTube REST API. *)
33+ This module provides functions for interacting with the PeerTube REST API.
44+*)
4556(** {1 Session} *)
6788+type t
79(** A PeerTube API session.
81099- Encapsulates the HTTP client and base URL for making API requests.
1010- In future, this may also contain authentication credentials. *)
1111-type t
1111+ Encapsulates the HTTP client and base URL for making API requests. In
1212+ future, this may also contain authentication credentials. *)
12131414+val create : session:Requests.t -> base_url:string -> t
1315(** [create ~session ~base_url] creates a new PeerTube API session.
14161517 @param session HTTP client session from the Requests library
1616- @param base_url Base URL of the PeerTube instance (e.g., "https://framatube.org") *)
1717-val create : session:Requests.t -> base_url:string -> t
1818+ @param base_url
1919+ Base URL of the PeerTube instance (e.g., "https://framatube.org") *)
18201919-(** [base_url t] returns the base URL of the PeerTube instance. *)
2021val base_url : t -> string
2222+(** [base_url t] returns the base URL of the PeerTube instance. *)
21232222-(** [http_session t] returns the underlying HTTP session. *)
2324val http_session : t -> Requests.t
2525+(** [http_session t] returns the underlying HTTP session. *)
24262527(** {1 Logging and Errors} *)
26282727-(** Log source for the PeerTube client. *)
2829val log_src : Logs.src
3030+(** Log source for the PeerTube client. *)
29313030-(** API error with HTTP status code and message. *)
3132exception Api_error of int * string
3333+(** API error with HTTP status code and message. *)
32343335(** {1 Video Operations} *)
34363737+val list_videos :
3838+ t ->
3939+ ?count:int ->
4040+ ?start:int ->
4141+ ?sort:Peertube_video_sort.t ->
4242+ ?nsfw:bool ->
4343+ ?is_local:bool ->
4444+ ?is_live:bool ->
4545+ ?category_id:int ->
4646+ ?tags:string ->
4747+ unit ->
4848+ Peertube_video.t Peertube_paginated.t
3549(** List videos with optional filtering and sorting.
36503751 @param count Number of videos per page (default: 20)
···4256 @param is_live Only live videos (default: None = both)
4357 @param category_id Filter by category ID
4458 @param tags Filter by tags (comma-separated) *)
4545-val list_videos :
5959+6060+val search_videos :
4661 t ->
6262+ query:string ->
4763 ?count:int ->
4864 ?start:int ->
4965 ?sort:Peertube_video_sort.t ->
5050- ?nsfw:bool ->
5151- ?is_local:bool ->
5252- ?is_live:bool ->
5353- ?category_id:int ->
5454- ?tags:string ->
6666+ ?search_target:[ `Local | `Search_index ] ->
6767+ ?duration_min:int ->
6868+ ?duration_max:int ->
6969+ ?published_after:Ptime.t ->
7070+ ?published_before:Ptime.t ->
5571 unit ->
5672 Peertube_video.t Peertube_paginated.t
5757-5873(** Search for videos.
59746075 @param query Search query string
···6681 @param duration_max Maximum duration in seconds
6782 @param published_after Only videos published after this date
6883 @param published_before Only videos published before this date *)
6969-val search_videos :
7070- t ->
7171- query:string ->
7272- ?count:int ->
7373- ?start:int ->
7474- ?sort:Peertube_video_sort.t ->
7575- ?search_target:[ `Local | `Search_index ] ->
7676- ?duration_min:int ->
7777- ?duration_max:int ->
7878- ?published_after:Ptime.t ->
7979- ?published_before:Ptime.t ->
8080- unit ->
8181- Peertube_video.t Peertube_paginated.t
82848383-(** Fetch videos from a channel with pagination. *)
8485val fetch_channel_videos :
8586 t ->
8687 ?count:int ->
···8889 channel:string ->
8990 unit ->
9091 Peertube_video.t Peertube_paginated.t
9292+(** Fetch videos from a channel with pagination. *)
91939292-(** Fetch all videos from a channel using automatic pagination. *)
9394val fetch_all_channel_videos :
9495 t ->
9596 ?page_size:int ->
···9798 channel:string ->
9899 unit ->
99100 Peertube_video.t list
101101+(** Fetch all videos from a channel using automatic pagination. *)
100102101101-(** Fetch detailed information for a single video by UUID. *)
102103val fetch_video_details : t -> uuid:string -> unit -> Peertube_video.t
104104+(** Fetch detailed information for a single video by UUID. *)
103105104104-(** Get available video categories. *)
105106val get_categories : t -> unit -> (int * string) list
107107+(** Get available video categories. *)
106108107107-(** Get available video licences. *)
108109val get_licences : t -> unit -> (int * string) list
110110+(** Get available video licences. *)
109111110110-(** Get available video languages. *)
111112val get_languages : t -> unit -> (string * string) list
113113+(** Get available video languages. *)
112114113115(** {1 Channel Operations} *)
114116115115-(** List all channels on the instance.
116116-117117- @param count Number per page (default: 20)
118118- @param start Starting offset (default: 0)
119119- @param sort Sort order: createdAt, -createdAt, etc. *)
120117val list_channels :
121118 t ->
122119 ?count:int ->
···124121 ?sort:string ->
125122 unit ->
126123 Peertube_channel.t Peertube_paginated.t
124124+(** List all channels on the instance.
127125128128-(** Search for channels.
126126+ @param count Number per page (default: 20)
127127+ @param start Starting offset (default: 0)
128128+ @param sort Sort order: createdAt, -createdAt, etc. *)
129129130130- @param query Search query string *)
131130val search_channels :
132131 t ->
133132 query:string ->
···135134 ?start:int ->
136135 unit ->
137136 Peertube_channel.t Peertube_paginated.t
137137+(** Search for channels.
138138139139-(** Get details for a specific channel. *)
139139+ @param query Search query string *)
140140+140141val get_channel : t -> handle:string -> unit -> Peertube_channel.t
142142+(** Get details for a specific channel. *)
141143142144(** {1 Account Operations} *)
143145144144-(** List accounts on the instance. *)
145146val list_accounts :
146147 t ->
147148 ?count:int ->
···149150 ?sort:string ->
150151 unit ->
151152 Peertube_account.t Peertube_paginated.t
153153+(** List accounts on the instance. *)
152154153153-(** Get details for a specific account. *)
154155val get_account : t -> handle:string -> unit -> Peertube_account.t
156156+(** Get details for a specific account. *)
155157156156-(** Get videos from a specific account. *)
157158val get_account_videos :
158159 t ->
159160 ?count:int ->
···161162 handle:string ->
162163 unit ->
163164 Peertube_video.t Peertube_paginated.t
165165+(** Get videos from a specific account. *)
164166165165-(** Get channels owned by an account. *)
166167val get_account_channels :
167168 t ->
168169 ?count:int ->
···170171 handle:string ->
171172 unit ->
172173 Peertube_channel.t Peertube_paginated.t
174174+(** Get channels owned by an account. *)
173175174176(** {1 Playlist Operations} *)
175177176176-(** List playlists on the instance. *)
177178val list_playlists :
178178- t -> ?count:int -> ?start:int -> unit -> Peertube_playlist.t Peertube_paginated.t
179179+ t ->
180180+ ?count:int ->
181181+ ?start:int ->
182182+ unit ->
183183+ Peertube_playlist.t Peertube_paginated.t
184184+(** List playlists on the instance. *)
179185180180-(** Search for playlists. *)
181186val search_playlists :
182187 t ->
183188 query:string ->
···185190 ?start:int ->
186191 unit ->
187192 Peertube_playlist.t Peertube_paginated.t
193193+(** Search for playlists. *)
188194189189-(** Get details for a specific playlist. *)
190195val get_playlist : t -> id:string -> unit -> Peertube_playlist.t
196196+(** Get details for a specific playlist. *)
191197192192-(** Get videos in a playlist. *)
193198val get_playlist_videos :
194199 t ->
195200 ?count:int ->
···197202 id:string ->
198203 unit ->
199204 Peertube_playlist_element.t Peertube_paginated.t
205205+(** Get videos in a playlist. *)
200206201201-(** Get playlists owned by an account. *)
202207val get_account_playlists :
203208 t ->
204209 ?count:int ->
···206211 handle:string ->
207212 unit ->
208213 Peertube_playlist.t Peertube_paginated.t
214214+(** Get playlists owned by an account. *)
209215210216(** {1 Server Operations} *)
211217212212-(** Get server configuration. *)
213218val get_config : t -> unit -> Peertube_server_config.t
219219+(** Get server configuration. *)
214220215215-(** Get server statistics. *)
216221val get_stats : t -> unit -> Peertube_server_stats.t
222222+(** Get server statistics. *)
217223218224(** {1 Utilities} *)
219225226226+val thumbnail_url : t -> Peertube_video.t -> string option
220227(** Get the full thumbnail URL for a video. *)
221221-val thumbnail_url : t -> Peertube_video.t -> string option
222228223223-(** Download a video's thumbnail to a file. *)
224229val download_thumbnail :
225230 t ->
226231 video:Peertube_video.t ->
227232 output_path:string ->
228233 unit ->
229234 (unit, [ `Msg of string ]) result
235235+(** Download a video's thumbnail to a file. *)
230236231231-(** Convert a video to a tuple for external use.
232232- Returns [(description, published_date, title, url, uuid, id_string)]. *)
233237val to_tuple :
234238 Peertube_video.t -> string * Ptime.t * string * string * string * string
239239+(** Convert a video to a tuple for external use. Returns
240240+ [(description, published_date, title, url, uuid, id_string)]. *)
···11(** Basic PeerTube server/instance information. *)
2233-(** Instance info type. *)
43type t
44+(** Instance info type. *)
5566-(** Create instance info. *)
76val make :
87 name:string ->
98 short_description:string ->
···1312 default_nsfw_policy:string ->
1413 default_client_route:string ->
1514 t
1515+(** Create instance info. *)
16161717+val name : t -> string
1718(** Instance name. *)
1818-val name : t -> string
19192020-(** Short description. *)
2120val short_description : t -> string
2121+(** Short description. *)
22222323+val description : t -> string option
2324(** Full description. *)
2424-val description : t -> string option
25252626-(** Terms of service. *)
2726val terms : t -> string option
2727+(** Terms of service. *)
28282929+val is_nsfw : t -> bool
2930(** Whether the instance is NSFW-focused. *)
3030-val is_nsfw : t -> bool
31313232-(** Default NSFW display policy. *)
3332val default_nsfw_policy : t -> string
3333+(** Default NSFW display policy. *)
34343535+val default_client_route : t -> string
3536(** Default client route. *)
3636-val default_client_route : t -> string
37373838+val jsont : t Jsont.t
3839(** JSON codec. *)
3939-val jsont : t Jsont.t
40404141-(** Pretty printer. *)
4241val pp : Format.formatter -> t -> unit
4242+(** Pretty printer. *)
+2-4
lib/peertube_labeled.ml
···1111 Jsont.Object.map ~kind:"int_labeled" make
1212 |> Jsont.Object.mem "id" Jsont.int ~enc:(fun l -> l.id)
1313 |> Jsont.Object.mem "label" Jsont.string ~enc:(fun l -> l.label)
1414- |> Jsont.Object.skip_unknown
1515- |> Jsont.Object.finish
1414+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
16151716let string_jsont : string t Jsont.t =
1817 let make id label = { id; label } in
1918 Jsont.Object.map ~kind:"string_labeled" make
2019 |> Jsont.Object.mem "id" Jsont.string ~enc:(fun l -> l.id)
2120 |> Jsont.Object.mem "label" Jsont.string ~enc:(fun l -> l.label)
2222- |> Jsont.Object.skip_unknown
2323- |> Jsont.Object.finish
2121+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
24222523let pp pp_id ppf t =
2624 Fmt.pf ppf "@[<hov 2>{ id = %a;@ label = %S }@]" pp_id t.id t.label
+9-9
lib/peertube_labeled.mli
···11(** Labeled values with an ID and display label.
2233- Used for categories, licences, languages, and other enumerated values
44- in the PeerTube API. *)
33+ Used for categories, licences, languages, and other enumerated values in the
44+ PeerTube API. *)
5566+type 'a t
67(** A labeled value with an ID and human-readable label. *)
77-type 'a t
8899-(** Create a labeled value. *)
109val make : id:'a -> label:string -> 'a t
1010+(** Create a labeled value. *)
11111212-(** Get the ID. *)
1312val id : 'a t -> 'a
1313+(** Get the ID. *)
14141515+val label : 'a t -> string
1516(** Get the label. *)
1616-val label : 'a t -> string
17171818-(** JSON codec for labeled values with int IDs. *)
1918val int_jsont : int t Jsont.t
1919+(** JSON codec for labeled values with int IDs. *)
20202121-(** JSON codec for labeled values with string IDs. *)
2221val string_jsont : string t Jsont.t
2222+(** JSON codec for labeled values with string IDs. *)
23232424-(** Pretty printer for labeled values. *)
2524val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit
2525+(** Pretty printer for labeled values. *)
+1-2
lib/peertube_paginated.ml
···1111 Jsont.Object.map ~kind make
1212 |> Jsont.Object.mem "total" Jsont.int ~enc:(fun r -> r.total)
1313 |> Jsont.Object.mem "data" (Jsont.list item_jsont) ~enc:(fun r -> r.data)
1414- |> Jsont.Object.skip_unknown
1515- |> Jsont.Object.finish
1414+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
16151716let pp pp_item ppf t =
1817 Fmt.pf ppf "@[<hov 2>{ total = %d;@ data = %a }@]" t.total
+6-6
lib/peertube_paginated.mli
···11(** Paginated API responses. *)
2233-(** A paginated response containing total count and data list. *)
43type 'a t
44+(** A paginated response containing total count and data list. *)
5566-(** Create a paginated response. *)
76val make : total:int -> data:'a list -> 'a t
77+(** Create a paginated response. *)
8899+val total : 'a t -> int
910(** Total number of items available. *)
1010-val total : 'a t -> int
11111212-(** Items in this page. *)
1312val data : 'a t -> 'a list
1313+(** Items in this page. *)
14141515-(** Create a JSON codec for paginated responses. *)
1615val jsont : kind:string -> 'a Jsont.t -> 'a t Jsont.t
1616+(** Create a JSON codec for paginated responses. *)
17171818+val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit
1819(** Pretty printer for paginated responses. *)
1919-val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit
···11(** PeerTube video playlist. *)
2233-(** Playlist type. *)
43type t
44+(** Playlist type. *)
5566-(** Create a playlist. *)
76val make :
87 id:int ->
98 uuid:string ->
···2019 owner_account:Peertube_account_summary.t option ->
2120 video_channel:Peertube_channel_summary.t option ->
2221 t
2222+(** Create a playlist. *)
23232424+val id : t -> int
2425(** Playlist ID. *)
2525-val id : t -> int
26262727-(** Playlist UUID. *)
2827val uuid : t -> string
2828+(** Playlist UUID. *)
29293030-(** Short UUID. *)
3130val short_uuid : t -> string option
3131+(** Short UUID. *)
32323333+val display_name : t -> string
3334(** Display name. *)
3434-val display_name : t -> string
35353636-(** Description. *)
3736val description : t -> string option
3737+(** Description. *)
38383939-(** Privacy level. *)
4039val privacy : t -> Peertube_playlist_privacy.t
4040+(** Privacy level. *)
41414242-(** Playlist URL. *)
4342val url : t -> string
4343+(** Playlist URL. *)
44444545-(** Thumbnail path (relative). *)
4645val thumbnail_path : t -> string option
4646+(** Thumbnail path (relative). *)
47474848+val videos_length : t -> int
4849(** Number of videos in playlist. *)
4949-val videos_length : t -> int
50505151+val playlist_type : t -> Peertube_playlist_type.t
5152(** Playlist type. *)
5252-val playlist_type : t -> Peertube_playlist_type.t
53535454-(** Creation timestamp. *)
5554val created_at : t -> Ptime.t
5555+(** Creation timestamp. *)
56565757-(** Last update timestamp. *)
5857val updated_at : t -> Ptime.t
5858+(** Last update timestamp. *)
59596060+val owner_account : t -> Peertube_account_summary.t option
6061(** Owner account. *)
6161-val owner_account : t -> Peertube_account_summary.t option
62626363-(** Associated video channel. *)
6463val video_channel : t -> Peertube_channel_summary.t option
6464+(** Associated video channel. *)
65656666-(** JSON codec. *)
6766val jsont : t Jsont.t
6767+(** JSON codec. *)
68686969-(** Pretty printer. *)
7069val pp : Format.formatter -> t -> unit
7070+(** Pretty printer. *)
+1-2
lib/peertube_playlist_element.ml
···3030 ~enc_omit:Option.is_none ~enc:(fun e -> e.stop_timestamp)
3131 |> Jsont.Object.mem "video" (Jsont.option Peertube_video.jsont)
3232 ~dec_absent:None ~enc_omit:Option.is_none ~enc:(fun e -> e.video)
3333- |> Jsont.Object.skip_unknown
3434- |> Jsont.Object.finish
3333+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
35343635let pp ppf t =
3736 Fmt.pf ppf "@[<hov 2>{ id = %d;@ position = %d;@ video = %a }@]" t.id
+9-9
lib/peertube_playlist_element.mli
···11(** An element in a PeerTube playlist. *)
2233-(** Playlist element type. *)
43type t
44+(** Playlist element type. *)
5566-(** Create a playlist element. *)
76val make :
87 id:int ->
98 position:int ->
···1110 stop_timestamp:int option ->
1211 video:Peertube_video.t option ->
1312 t
1313+(** Create a playlist element. *)
14141515+val id : t -> int
1516(** Element ID. *)
1616-val id : t -> int
17171818-(** Position in playlist (0-indexed). *)
1918val position : t -> int
1919+(** Position in playlist (0-indexed). *)
20202121-(** Start timestamp in seconds. *)
2221val start_timestamp : t -> int option
2222+(** Start timestamp in seconds. *)
23232424+val stop_timestamp : t -> int option
2425(** Stop timestamp in seconds. *)
2525-val stop_timestamp : t -> int option
26262727-(** The video. *)
2827val video : t -> Peertube_video.t option
2828+(** The video. *)
29293030-(** JSON codec. *)
3130val jsont : t Jsont.t
3131+(** JSON codec. *)
32323333-(** Pretty printer. *)
3433val pp : Format.formatter -> t -> unit
3434+(** Pretty printer. *)
···33(** Playlist type. *)
44type t = Regular | WatchLater
5566-(** Convert type to its integer representation. *)
76val to_int : t -> int
77+(** Convert type to its integer representation. *)
8899-(** Convert integer to playlist type. *)
109val of_int : int -> t
1010+(** Convert integer to playlist type. *)
11111212-(** JSON codec for playlist type. *)
1312val jsont : t Jsont.t
1313+(** JSON codec for playlist type. *)
14141515-(** Pretty printer for playlist type. *)
1615val pp : Format.formatter -> t -> unit
1616+(** Pretty printer for playlist type. *)
+6-3
lib/peertube_privacy.ml
···2233type t = Public | Unlisted | Private | Internal
4455-let to_int = function Public -> 1 | Unlisted -> 2 | Private -> 3 | Internal -> 4
55+let to_int = function
66+ | Public -> 1
77+ | Unlisted -> 2
88+ | Private -> 3
99+ | Internal -> 4
610711let of_int = function
812 | 1 -> Public
···1620 Jsont.Object.map ~kind:"privacy" make
1721 |> Jsont.Object.mem "id" Jsont.int ~enc:to_int
1822 |> Jsont.Object.mem "label" Jsont.string ~dec_absent:"" ~enc:(Fun.const "")
1919- |> Jsont.Object.skip_unknown
2020- |> Jsont.Object.finish
2323+ |> Jsont.Object.skip_unknown |> Jsont.Object.finish
21242225let pp ppf = function
2326 | Public -> Fmt.string ppf "Public"
+4-4
lib/peertube_privacy.mli
···33(** Video privacy level. *)
44type t = Public | Unlisted | Private | Internal
5566-(** Convert privacy to its integer representation. *)
76val to_int : t -> int
77+(** Convert privacy to its integer representation. *)
8899-(** Convert integer to privacy level. *)
109val of_int : int -> t
1010+(** Convert integer to privacy level. *)
11111212-(** JSON codec for privacy. *)
1312val jsont : t Jsont.t
1313+(** JSON codec for privacy. *)
14141515-(** Pretty printer for privacy. *)
1615val pp : Format.formatter -> t -> unit
1616+(** Pretty printer for privacy. *)
+2-2
lib/peertube_ptime.mli
···11(** Ptime JSON codec for RFC3339 date strings. *)
2233-(** JSON codec for Ptime.t values encoded as RFC3339 strings. *)
43val jsont : Ptime.t Jsont.t
44+(** JSON codec for Ptime.t values encoded as RFC3339 strings. *)
5566-(** Pretty printer for Ptime.t values. *)
76val pp : Format.formatter -> Ptime.t -> unit
77+(** Pretty printer for Ptime.t values. *)
···11(** PeerTube server statistics. *)
2233-(** Server stats type. *)
43type t
44+(** Server stats type. *)
5566-(** Create server stats. *)
76val make :
87 total_users:int ->
98 total_daily_active_users:int ->
···2019 total_instance_followers:int ->
2120 total_instance_following:int ->
2221 t
2222+(** Create server stats. *)
23232424+val total_users : t -> int
2425(** Total registered users. *)
2525-val total_users : t -> int
26262727-(** Daily active users. *)
2827val total_daily_active_users : t -> int
2828+(** Daily active users. *)
29293030-(** Weekly active users. *)
3130val total_weekly_active_users : t -> int
3131+(** Weekly active users. *)
32323333+val total_monthly_active_users : t -> int
3334(** Monthly active users. *)
3434-val total_monthly_active_users : t -> int
35353636-(** Total local videos. *)
3736val total_local_videos : t -> int
3737+(** Total local videos. *)
38383939-(** Total local video views. *)
4039val total_local_video_views : t -> int
4040+(** Total local video views. *)
41414242-(** Total local video comments. *)
4342val total_local_video_comments : t -> int
4343+(** Total local video comments. *)
44444545-(** Total local video files size in bytes. *)
4645val total_local_video_files_size : t -> int64
4646+(** Total local video files size in bytes. *)
47474848+val total_videos : t -> int
4849(** Total videos (including federated). *)
4949-val total_videos : t -> int
50505151+val total_video_comments : t -> int
5152(** Total video comments (including federated). *)
5252-val total_video_comments : t -> int
53535454-(** Total local video channels. *)
5554val total_local_video_channels : t -> int
5555+(** Total local video channels. *)
56565757-(** Total local playlists. *)
5857val total_local_playlists : t -> int
5858+(** Total local playlists. *)
59596060+val total_instance_followers : t -> int
6061(** Total instance followers. *)
6161-val total_instance_followers : t -> int
62626363-(** Total instances being followed. *)
6463val total_instance_following : t -> int
6464+(** Total instances being followed. *)
65656666-(** JSON codec. *)
6766val jsont : t Jsont.t
6767+(** JSON codec. *)
68686969-(** Pretty printer. *)
7069val pp : Format.formatter -> t -> unit
7070+(** Pretty printer. *)
···11(** PeerTube video record. *)
2233-(** Video type. *)
43type t
44+(** Video type. *)
5566-(** Create a video. *)
76val make :
87 id:int ->
98 uuid:string ->
···3130 channel:Peertube_channel_summary.t option ->
3231 account:Peertube_account_summary.t option ->
3332 t
3333+(** Create a video. *)
34343535+val id : t -> int
3536(** Video ID. *)
3636-val id : t -> int
37373838-(** Video UUID. *)
3938val uuid : t -> string
3939+(** Video UUID. *)
40404141-(** Short UUID. *)
4241val short_uuid : t -> string option
4242+(** Short UUID. *)
43434444+val name : t -> string
4445(** Video title. *)
4545-val name : t -> string
46464747-(** Video description. *)
4847val description : t -> string option
4848+(** Video description. *)
49495050+val url : t -> string
5051(** Video URL. *)
5151-val url : t -> string
52525353-(** Embed path. *)
5453val embed_path : t -> string
5454+(** Embed path. *)
55555656+val published_at : t -> Ptime.t
5657(** Publication timestamp. *)
5757-val published_at : t -> Ptime.t
58585959+val originally_published_at : t -> Ptime.t option
5960(** Original publication timestamp. *)
6060-val originally_published_at : t -> Ptime.t option
61616262-(** Last update timestamp. *)
6362val updated_at : t -> Ptime.t option
6363+(** Last update timestamp. *)
64646565-(** Thumbnail path (relative). *)
6665val thumbnail_path : t -> string option
6666+(** Thumbnail path (relative). *)
67676868-(** Preview path (relative). *)
6968val preview_path : t -> string option
6969+(** Preview path (relative). *)
70707171-(** Video tags. *)
7271val tags : t -> string list
7272+(** Video tags. *)
73737474-(** Duration in seconds. *)
7574val duration : t -> int
7575+(** Duration in seconds. *)
76767777-(** View count. *)
7877val views : t -> int
7878+(** View count. *)
79798080-(** Like count. *)
8180val likes : t -> int
8181+(** Like count. *)
82828383+val dislikes : t -> int
8384(** Dislike count. *)
8484-val dislikes : t -> int
85858686-(** Whether the video is local to this instance. *)
8786val is_local : t -> bool
8787+(** Whether the video is local to this instance. *)
88888989+val is_live : t -> bool
8990(** Whether this is a live stream. *)
9090-val is_live : t -> bool
91919292+val privacy : t -> Peertube_privacy.t
9293(** Privacy level. *)
9393-val privacy : t -> Peertube_privacy.t
94949595-(** Video category. *)
9695val category : t -> int Peertube_labeled.t option
9696+(** Video category. *)
97979898-(** Video licence. *)
9998val licence : t -> int Peertube_labeled.t option
9999+(** Video licence. *)
100100101101-(** Video language. *)
102101val language : t -> string Peertube_labeled.t option
102102+(** Video language. *)
103103104104-(** Channel that published the video. *)
105104val channel : t -> Peertube_channel_summary.t option
105105+(** Channel that published the video. *)
106106107107-(** Account that published the video. *)
108107val account : t -> Peertube_account_summary.t option
108108+(** Account that published the video. *)
109109110110+val jsont : t Jsont.t
110111(** JSON codec. *)
111111-val jsont : t Jsont.t
112112113113+val pp : Format.formatter -> t -> unit
113114(** Pretty printer. *)
114114-val pp : Format.formatter -> t -> unit
+2-2
lib/peertube_video_sort.mli
···33(** Video sort order. *)
44type t = Newest | Oldest | Views | Likes | Trending | Hot | Random | Best
5566-(** Convert sort option to API query string. *)
76val to_string : t -> string
77+(** Convert sort option to API query string. *)
8899-(** Pretty printer for sort options. *)
109val pp : Format.formatter -> t -> unit
1010+(** Pretty printer for sort options. *)
+4-4
peertube.opam
···22opam-version: "2.0"
33synopsis: "PeerTube API client for OCaml using Eio"
44description:
55- "An OCaml client library for the PeerTube video platform API, built on Eio for effect-based I/O"
55+ "An OCaml client library for the PeerTube video platform API, built on Eio for effect-based I/O. Includes a command-line client (opeertube) for browsing videos, channels, accounts, and playlists."
66maintainer: ["anil@recoil.org"]
77authors: ["Anil Madhavapeddy"]
88license: "ISC"
99-homepage: "https://github.com/avsm/ocaml-peertube"
1010-bug-reports: "https://github.com/avsm/ocaml-peertube/issues"
99+homepage: "https://git.recoil.org/anil.recoil.org/ocaml-peertube"
1010+bug-reports: "https://git.recoil.org/anil.recoil.org/ocaml-peertube/issues"
1111depends: [
1212 "dune" {>= "3.16"}
1313 "ocaml" {>= "5.1.0"}
···3535 "@doc" {with-doc}
3636 ]
3737]
3838-dev-repo: "git+https://github.com/avsm/ocaml-peertube.git"
3838+dev-repo: "https://git.recoil.org/anil.recoil.org/ocaml-peertube"