Skip to content

Instantly share code, notes, and snippets.

@ruxo
Created November 26, 2024 10:30
Show Gist options
  • Save ruxo/893f41dd497cea0fd1cacb92ceac1f8d to your computer and use it in GitHub Desktop.
Save ruxo/893f41dd497cea0fd1cacb92ceac1f8d to your computer and use it in GitHub Desktop.
// #r "nuget: TiraxTech.Uri"
open System
open System.Net
open System.Net.Http
open System.Text.Json
open Microsoft.Extensions.Primitives
open RZ.Foundation.Json
open TiraxTech
type Uri = TiraxTech.Uri
let private TidalApiUrl = Uri.From "https://openapi.tidal.com/v2/"
let configureHttpClient token (http: HttpClient) =
http.BaseAddress <- TidalApiUrl.ToSystemUri()
http.DefaultRequestHeaders.Add("Authorization", $"Bearer %s{token}")
http.DefaultRequestVersion <- HttpVersion.Version30
http.DefaultVersionPolicy <- HttpVersionPolicy.RequestVersionOrLower
http
let private JsonOptions = JsonSerializerOptions(JsonSerializerDefaults.Web).UseRzRecommendedSettings()
type RecordLinks = {
Self: string
Next: string option
}
type DataRecords<'a> = {
Data: 'a list
Links: RecordLinks option
}
type GenericResource<'T> = {
Id: string
``type``: string
Attributes: 'T
}
let get<'a> url (http: HttpClient) =
http |> RZ.Http.getJson<DataRecords<'a>> JsonOptions url
let fetchNext (data: DataRecords<'a>) (http: HttpClient) = async {
match data.Links |> Option.bind _.Next with
| Some next -> return! http |> get<'a> next[1..]
| None -> return { Data=[]; Links=None }
}
// ---------------------------------------- PLAYLIST ----------------------------------------
type PlaylistAttributes = {
Name: string
Description: string
NumberOfItems: int
CreatedAt: DateTimeOffset
LastModifiedAt: DateTimeOffset
}
type Playlist = {
Id: string
Attributes: PlaylistAttributes
}
let [<Literal>] private GetMyPlaylistsUrl = "playlists/me"
let getMyPlaylists http =
http |> get<Playlist> GetMyPlaylistsUrl
// ---------------------------------------- TRACKS ----------------------------------------
type TrackMeta = {
ItemId: string
AddedAt: DateTimeOffset
}
type TrackItem = {
Id: string
Meta: TrackMeta
}
let [<Literal>] private GetTrackUrl = "playlists/%s/relationships/items"
let getTrackItems playlist_id http =
http |> get<TrackItem> (sprintf GetTrackUrl playlist_id)
// ---------------------------------------- TRACK DETAILS ----------------------------------------
type TrackDetails = {
Title: string
iSrc: string
}
type TrackRelationshipItem = { Links: RecordLinks }
type TrackRelationships = {
Albums: TrackRelationshipItem
Artists: TrackRelationshipItem
}
type Track = {
Id: string
Attributes: TrackDetails
Relationships: TrackRelationships
}
let private GetTracksDetailsUrl = RelativeUri.From "tracks?countryCode=TH&filter[isrc]="
let getTracksInfo track_ids http = async {
let url = GetTracksDetailsUrl.UpdateQuery("filter[id]", StringValues(track_ids |> Seq.toArray)).ToString()
return! http |> get<Track> url
}
// ---------------------------------------- ALBUM DETAILS ----------------------------------------
type AlbumDetails = {
Title: string
BarcodeId: string
}
let private GetAlbumDetailsUrl = RelativeUri.From "albums?countryCode=TH"
let getAlbumInfo (album_id: string) http = async {
let url = GetAlbumDetailsUrl.UpdateQuery("filter[id]", StringValues album_id).ToString()
return! http |> get<GenericResource<AlbumDetails>> url
}
// ---------------------------------------- ARTIST DETAILS ----------------------------------------
type ArtistDetails = {
Name: string
Popularity: float
}
let private GetArtistDetailsUrl = RelativeUri.From "artists?countryCode=TH"
let getArtistInfo (artist_id: string) http = async {
let url = GetArtistDetailsUrl.UpdateQuery("filter[id]", StringValues artist_id).ToString()
return! http |> get<GenericResource<ArtistDetails>> url
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment