Current section
Files
Jump to
Current section
Files
src/midas/sdk/vimeo.gleam
import gleam/bit_array
import gleam/dynamic
import gleam/http
import gleam/http/request
import gleam/http/response
import gleam/int
import gleam/json
import gleam/list
import gleam/option.{None, Some}
import gleam/result.{try}
import gleam/string
import gleam/uri.{Uri}
import midas/task as t
import snag
pub type App {
App(client_id: String, redirect_uri: String)
}
const auth_host = api_host
const auth_path = "/oauth/authorize"
pub fn authenticate(app, scopes) {
let App(client_id, redirect_uri) = app
let state = int.to_string(int.random(1_000_000_000))
let url = auth_url(client_id, redirect_uri, state, scopes)
use redirect <- t.do(t.follow(url))
use #(access_token, token_type, returned_state) <- t.try(
auth_redirect(redirect) |> result.map_error(snag.new),
)
use Nil <- t.try(case returned_state == state {
True -> Ok(Nil)
False -> Error(snag.new("returned state was not equal to sent state"))
})
use Nil <- t.try(case string.lowercase(token_type) == "bearer" {
True -> Ok(Nil)
False ->
Error(snag.new("returned token_type was not 'Bearer'" <> token_type))
})
t.Done(access_token)
}
fn auth_url(client_id, redirect_uri, state, scopes) {
let query = [
#("client_id", client_id),
#("response_type", "token"),
#("redirect_uri", redirect_uri),
#("state", state),
#("scope", string.join(scopes, " ")),
]
let query = Some(uri.query_to_string(query))
Uri(Some("https"), None, Some(auth_host), None, auth_path, query, None)
|> uri.to_string
}
pub fn auth_redirect(redirect) {
let Uri(fragment: fragment, ..) = redirect
use hash <- try(case fragment {
Some(hash) -> Ok(hash)
None -> Error("uri did not have a fragment")
})
use parts <- try(
uri.parse_query(hash)
|> result.replace_error("Failed to parse query: " <> hash),
)
use access_token <- try(key_find(parts, "access_token"))
use token_type <- try(key_find(parts, "token_type"))
use returned_state <- try(key_find(parts, "state"))
Ok(#(access_token, token_type, returned_state))
}
fn key_find(items, key) {
list.key_find(items, key)
|> result.replace_error("Did not find key: " <> key)
}
const api_host = "api.vimeo.com"
fn base_request(token) {
request.new()
|> request.set_host(api_host)
|> request.prepend_header("Authorization", string.append("Bearer ", token))
}
fn get(token, path) {
base_request(token)
|> request.set_path(path)
|> request.set_body(<<>>)
}
fn post(token, path, mime, content) {
base_request(token)
|> request.set_method(http.Post)
|> request.set_path(path)
|> request.prepend_header("content-type", mime)
|> request.set_body(content)
}
pub fn my_videos(token) {
let request = my_videos_request(token)
use response <- t.do(t.fetch(request))
use response <- t.try(my_videos_response(response))
t.Done(response)
}
pub fn my_videos_request(token) {
let path = "/me/videos"
get(token, path)
}
pub fn my_videos_response(response: response.Response(BitArray)) {
use json <- try(
bit_array.to_string(response.body)
|> result.replace_error(snag.new("not utf8 encoded")),
)
let decoder = dynamic.field("data", dynamic.list(video_decoder))
use videos <- try(
json.decode_bits(response.body, decoder)
|> result.replace_error(snag.new("failed to decode vieos")),
)
Ok(videos)
}
pub type Video {
Video(
name: String,
link: String,
duration: Int,
created_time: String,
plays: Int,
has_audio: Bool,
)
}
pub fn video_decoder(data) {
dynamic.decode6(
Video,
dynamic.field("name", dynamic.string),
dynamic.field("link", dynamic.string),
dynamic.field("duration", dynamic.int),
dynamic.field("created_time", dynamic.string),
dynamic.field("stats", dynamic.field("plays", dynamic.int)),
dynamic.field("has_audio", dynamic.bool),
)(data)
}