ITQF7AQWZNN733JQHK3PHYDWDGM4JJZVFBLB7F7XPS56PMHCKTMQC
AYSPIRRQNBESKXOVILHY4QEIZA37AOFFT5KY75GKZJIPUXD62UIQC
LB4HIYWKTVYQPH77VAQCFOXNO7JD72SMXTK2U6G7UC2MDQM6VHPAC
HMJFS6WWD2JJZB57HBXRHYS2A2N25YDDAJ443KRMT6K3ALHIBRVQC
FEHWT3MOW3STJXNBQWXSY6ZDSJIJWVU6EWCXA6KARH7DCYFNM5NQC
P35HCXDOT4NKKPTM6OMKEVKBLB3VLEODS7LNKRG7777RLOFDGU2AC
B22T6OTOYMTCUQJGC4DVNB2FNKIYQHLU3I7H2OBWTNLX5WT2Y5RQC
WWOXTYSKCYOBP6H7OQNLZJ22O6WVWCHQNJTHBRQ3ZEJH2KSQF3UAC
MGOB3WXKVDFPE5PPKWC4EEST2CR4NQ7B2FASVYHO5JNNGXC5NNPAC
let* s = D.Audio_stream.Ffmpeg.of_file "./bite2.mp3" in
let* s = D.Audio_stream.Ffmpeg.create "./bite2.mp3" in
match s with
| Ok audio_stream ->
D.Client.play_audio_stream ~guild_id audio_stream client
| _ -> Lwt.return_unit)
| Some ("play", "allstar") -> (
let guild_id = Option.get_exn guild_id in
let* s = D.Audio_stream.Ffmpeg.create "./allstar.mp3" in
| Some ("play", query) -> (
let guild_id = Option.get_exn guild_id in
let* tracks = Ytdl.query query in
match tracks with
| Ok [] | Error _ ->
let msg = Msg.fmt "⚠️ No track found for query: '%s'" query in
D.Client.send_message channel_id msg client
| Ok (track :: _) -> (
let* s = D.Audio_stream.Ffmpeg.create track.url in
match s with
| Ok audio_stream ->
let* () =
D.Client.play_audio_stream ~guild_id audio_stream client
in
let msg =
Msg.fmt "🎵 @{<b>Now playing:@} '%s'\n%s" track.title
track.thumbnail
in
D.Client.send_message channel_id msg client
| Error e ->
client
|> D.Client.send_message channel_id
(Msg.fmt "⚠️ Couldn't play track: '%s'\nReason: %a"
track.title D.Error.pp e)))
| Some ("pause", _) ->
let _guild_id = Option.get_exn guild_id in
Lwt.return_unit
open Containers
open Lwt.Infix
module L = (val Relog.logger ~namespace:__MODULE__ ())
type track = { title : string; url : string; thumbnail : string }
let args =
[ "--default-search"; "ytsearch1:"; "-f"; "webm[abr>0]/bestaudio/best"; "-j" ]
let query q =
let cmd = "youtube-dl" in
let playlist = String.find ~sub:"list=" q <> -1 in
let args = args @ [ q ] in
let args = if playlist then "--flat-playlist" :: args else args in
let cmd_str = cmd :: args |> List.to_string ~sep:" " Fun.id in
L.info (fun m -> m "running cmd: %s" cmd_str);
Lwt_process.with_process_full
("", Array.of_list @@ cmd :: args)
(fun proc ->
let _logs () = Lwt_io.read proc#stderr in
L.info (fun m -> m "youtube-dl running with pid=%d" proc#pid);
(Lwt_io.read_line proc#stdout |> Lwt_result.catch >|= function
| Error End_of_file -> Ok []
| Error exn -> Discord.Error.exn exn
| Ok track ->
let info = Yojson.Safe.from_string track in
let title = Yojson.Safe.Util.(member "title" info |> to_string) in
let url = Yojson.Safe.Util.(member "url" info |> to_string) in
let thumbnail =
Yojson.Safe.Util.(member "thumbnail" info |> to_string)
in
Ok [ { title; url; thumbnail } ])
>>= fun res ->
proc#close >|= fun _ -> res)
"@opam/ppx_bitstring@opam:4.1.0@ded0b52e": {
"id": "@opam/ppx_bitstring@opam:4.1.0@ded0b52e",
"name": "@opam/ppx_bitstring",
"version": "opam:4.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/8a/8ae6f04eaa29481c6830ee3be5cba755#md5:8ae6f04eaa29481c6830ee3be5cba755",
"archive:https://github.com/xguerin/bitstring/archive/v4.1.0.tar.gz#md5:8ae6f04eaa29481c6830ee3be5cba755"
],
"opam": {
"name": "ppx_bitstring",
"version": "4.1.0",
"path": "esy.lock/opam/ppx_bitstring.4.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/dune@opam:2.8.4@1490e2a1",
"@opam/bitstring@opam:4.1.0@1d9e964d",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/dune@opam:2.8.4@1490e2a1",
"@opam/bitstring@opam:4.1.0@1d9e964d"
]
},
"archive:https://opam.ocaml.org/cache/sha256/ce/cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb#sha256:cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb",
"archive:https://github.com/ocaml/ocaml-lsp/releases/download/1.4.1/jsonrpc-1.4.1.tbz#sha256:cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb"
"archive:https://opam.ocaml.org/cache/md5/2c/2c19731536a4f62923554c1947c39211#md5:2c19731536a4f62923554c1947c39211",
"archive:https://github.com/ocaml/ocaml-lsp/releases/download/1.5.0/jsonrpc-1.5.0.tbz#md5:2c19731536a4f62923554c1947c39211"
"archive:https://opam.ocaml.org/cache/sha256/9e/9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d#sha256:9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d",
"archive:https://github.com/ocaml/merlin/releases/download/v4.1-411/merlin-v4.1-411.tbz#sha256:9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d"
"archive:https://opam.ocaml.org/cache/sha256/fb/fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d#sha256:fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d",
"archive:https://github.com/ocaml/merlin/releases/download/v4.1-412/merlin-v4.1-412.tbz#sha256:fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d"
"@opam/bitstring@opam:4.1.0@1d9e964d": {
"id": "@opam/bitstring@opam:4.1.0@1d9e964d",
"name": "@opam/bitstring",
"version": "opam:4.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/8a/8ae6f04eaa29481c6830ee3be5cba755#md5:8ae6f04eaa29481c6830ee3be5cba755",
"archive:https://github.com/xguerin/bitstring/archive/v4.1.0.tar.gz#md5:8ae6f04eaa29481c6830ee3be5cba755"
],
"opam": {
"name": "bitstring",
"version": "4.1.0",
"path": "esy.lock/opam/bitstring.4.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/dune@opam:2.8.4@1490e2a1", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/dune@opam:2.8.4@1490e2a1"
]
},
opam-version: "2.0"
synopsis: "Bitstrings and bitstring matching for OCaml"
description: """
The ocaml-bitstring project adds Erlang-style bitstrings and matching over bitstrings as a syntax extension and library for OCaml.
You can use this module to both parse and generate binary formats, files and protocols.
Bitstring handling is added as primitives to the language, making it exceptionally simple to use and very powerful.
"""
maintainer: ["Xavier R. Guérin <github@applepine.org>"]
authors: ["Richard W.M. Jones" "Xavier R. Guérin"]
license: "LGPL-2.0-or-later"
homepage: "https://github.com/xguerin/bitstring"
bug-reports: "https://github.com/xguerin/bitstring/issues"
depends: [
"dune" {>= "2.5"}
"ocaml" {>= "4.04.1"}
"stdlib-shims" {>= "0.1.0"}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/xguerin/bitstring.git"
url {
src: "https://github.com/xguerin/bitstring/archive/v4.1.0.tar.gz"
checksum: "md5=8ae6f04eaa29481c6830ee3be5cba755"
}
opam-version: "2.0"
synopsis: "Bitstrings and bitstring matching for OCaml - PPX extension"
description: """
The ocaml-bitstring project adds Erlang-style bitstrings and matching over bitstrings as a syntax extension and library for OCaml.
You can use this module to both parse and generate binary formats, files and protocols.
Bitstring handling is added as primitives to the language, making it exceptionally simple to use and very powerful.
"""
maintainer: ["Xavier R. Guérin <github@applepine.org>"]
authors: ["Richard W.M. Jones" "Xavier R. Guérin"]
license: "LGPL-2.0-or-later"
homepage: "https://github.com/xguerin/bitstring"
bug-reports: "https://github.com/xguerin/bitstring/issues"
depends: [
"dune" {>= "2.5"}
"ocaml" {>= "4.04.1"}
"bitstring" {>= "4.0.0"}
"ocaml" {with-test & >= "4.08.0"}
"ppxlib" {>= "0.18.0"}
"ounit" {with-test}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/xguerin/bitstring.git"
url {
src: "https://github.com/xguerin/bitstring/archive/v4.1.0.tar.gz"
checksum: "md5=8ae6f04eaa29481c6830ee3be5cba755"
}
"sha256=9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d"
"sha512=6a2e2503d81b22b0cc292ca6853231e59c42a216acec0cb540d03791d201fe83641a3502e62660668ad5d30405698e2429efe072cfd38dc30229024267f7c0b8"
"sha256=fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d"
"sha512=ec301e0f97e11c1c331478030372d373d381a0ddbb7f72c83f7baa4c2c6d4f26094c3398f56bcf3d40c1242044391369fd06e8cd2ccfe1f5d78467eb3e9d33be"
"sha256=cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb"
"sha512=150ebf71d3484d3beec1a145877cf30d84581bd072dd20159e878ed07cc4fc647b019b98bb0c9fede839b87f7bd13de4a64b534c0760a2ec57d0e4a4deac6f0f"
"md5=2c19731536a4f62923554c1947c39211"
"sha512=9bc252e2564fe6c9017b5ee1b2c4ddebf73c4be4b2a3d48f1d61b6ec1910a2cb9f4fa4952a7a6d89482c28ddbad8e0d9c34c206a1b2fe42bb2c3a7156aa953e9"
play frame >>= fun ok ->
if ok then exhaust ~i:(i + 1) p
else if i = 0 then failwith "need to send at least 1 frame"
else Lwt.return (`Yield i)
play (i + 1) frame >>= fun ok ->
let i = i + 1 in
if ok then exhaust ~i p else Lwt.return (`Yield i)
Encoder.create ~samplerate:Rtp._SAMPLE_RATE ~channels:`stereo
~application:`Audio ()
>>= (fun enc ->
let shared =
CTL.
[
Set_signal `Music;
Set_bitrate `Max;
Set_complexity 10;
Set_packet_loss_perc 5;
Set_complexity 10;
Set_inband_FEC true;
Set_DTX false;
]
in
let ctls =
match frametype with
| `s16 -> CTL.(Set_LSB_depth 16) :: shared
| `f32 -> CTL.(Set_LSB_depth 24) :: shared
in
set_ctls ~l:ctls enc)
|> Result.map_err (fun e ->
`Msg (Printf.sprintf "opus error: %s" (Opus.Error.to_string e)))
Opus.(
Encoder.create ~samplerate:Rtp._SAMPLE_RATE ~channels:`stereo
~application:`Audio ()
>>= fun enc ->
let shared =
CTL.
[
Set_signal `Music;
Set_bitrate `Max;
Set_complexity 10;
Set_packet_loss_perc 5;
Set_inband_FEC true;
Set_DTX false;
]
in
let ctls =
match frametype with
| `s16 -> CTL.(Set_LSB_depth 16) :: shared
| `f32 -> CTL.(Set_LSB_depth 24) :: shared
in
set_ctls ~l:ctls enc)
|> function
| Error e -> Error.msgf "opus error: %a" Opus.Error.pp e
| Ok v -> Ok v
let curr = ref 0 in
let play frame =
if !curr < burst then (
Voice.start_speaking voice >>= fun () ->
Voice.send_rtp voice frame >|= fun () ->
incr curr;
true)
else (
curr := 0;
Lwt.return false)
let play i frame =
Voice.start_speaking voice >>= fun () ->
Voice.send_rtp voice frame >|= fun () -> i < burst