A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz
0

Configure Feed

Select the types of activity you want to include in your feed.

rocksky / sdk / elixir / lib / rocksky.ex
6.7 kB 172 lines
1defmodule Rocksky do 2 @moduledoc """ 3 Official Elixir SDK for Rocksky. 4 5 A thin wrapper over the `:rocksky_erl` Rustler NIF (the shared Rust core, 6 `rocksky-sdk`): AppView reads, AT Protocol PDS writes (scrobble fan-out, like, 7 follow, shout) and the identity hashes — the same engine behind every Rocksky 8 SDK. 9 10 Reads/writes return `{:ok, value}` | `{:error, message}` with binary-keyed 11 maps (the wire shape). Records passed to the write verbs are maps with 12 camelCase binary keys — `"title"`, `"artist"`, `"album"`, `"albumArtist"`, 13 `"durationMs"`, … 14 15 {:ok, stats} = Rocksky.global_stats() 16 Rocksky.song_hash("Chaser", "Calibro 35", "Jazzploitation") 17 """ 18 19 # ---- reads (unauthenticated; trailing base overrides the AppView URL) ---- 20 21 @doc "An actor's detailed profile." 22 def profile(actor, base \\ ""), do: :rocksky.profile(to_bin(actor), to_bin(base)) 23 24 @doc "An actor's scrobbles, newest first." 25 def scrobbles(actor, limit \\ 50, offset \\ 0, base \\ ""), 26 do: :rocksky.scrobbles(to_bin(actor), limit, offset, to_bin(base)) 27 28 @doc "Platform-wide top tracks chart." 29 def top_tracks(limit \\ 50, offset \\ 0, base \\ ""), 30 do: :rocksky.top_tracks(limit, offset, to_bin(base)) 31 32 @doc "Platform-wide totals." 33 def global_stats(base \\ ""), do: :rocksky.global_stats(to_bin(base)) 34 35 @doc """ 36 Universal read escape hatch — call any `app.rocksky.*` query by nsid. 37 38 `params` is a map of string params; the whole read-query catalog is reachable. 39 40 Rocksky.get("app.rocksky.album.getAlbum", %{"uri" => uri}) 41 Rocksky.get("app.rocksky.charts.getScrobblesChart", %{"did" => did}) 42 """ 43 def get(nsid, params \\ %{}, base \\ "", token \\ ""), 44 do: :rocksky.get(to_bin(nsid), params, to_bin(base), to_bin(token)) 45 46 @doc """ 47 The authenticated viewer's unread-notification count (`token` required). 48 Returns `%{"count" => n}`. 49 """ 50 def unread_count(token, base \\ ""), 51 do: :rocksky.unread_count(to_bin(token), to_bin(base)) 52 53 @doc """ 54 The authenticated viewer's notifications, most recent first (`token` required). 55 `params` may include `"limit"` (default 30) and `"cursor"`. 56 """ 57 def notifications(token, params \\ %{}, base \\ ""), 58 do: :rocksky.notifications(to_bin(token), params, to_bin(base)) 59 60 @doc """ 61 Mark notifications as viewed (`token` required). `ids` is a list of notification 62 ids, or `[]` to mark all. Returns `%{"unreadCount" => n}`. 63 """ 64 def update_seen(token, ids \\ [], base \\ ""), 65 do: :rocksky.update_seen(to_bin(token), ids, to_bin(base)) 66 67 @doc "Resolve full canonical metadata for a bare title + artist (matchSong)." 68 def match_song(title, artist, mb_id \\ "", isrc \\ "", base \\ ""), 69 do: :rocksky.match_song(to_bin(base), to_bin(title), to_bin(artist), to_bin(mb_id), to_bin(isrc)) 70 71 @doc """ 72 Top tracks chart over a typed date window. 73 74 `interval` is `:all` | `{:days, n}` | `{:weeks, n}` | `{:months, n}` | 75 `{:years, n}` | `{:range, start_rfc3339, end_rfc3339}`. 76 77 Rocksky.top_tracks_interval(10, 0, {:days, 7}) 78 """ 79 def top_tracks_interval(limit \\ 50, offset \\ 0, interval \\ :all, base \\ ""), 80 do: :rocksky.top_tracks_interval(limit, offset, interval, to_bin(base)) 81 82 @doc "Top artists chart over a typed date window (see `top_tracks_interval/4`)." 83 def top_artists_interval(limit \\ 50, offset \\ 0, interval \\ :all, base \\ ""), 84 do: :rocksky.top_artists_interval(limit, offset, interval, to_bin(base)) 85 86 @doc "Identity hash of a song — identical across every Rocksky SDK." 87 def song_hash(title, artist, album), 88 do: :rocksky.song_hash(to_bin(title), to_bin(artist), to_bin(album)) 89 90 # ---- authenticated agent ------------------------------------------------- 91 92 @doc """ 93 Log in with an app password, persisting the session at `session_path`. 94 Returns an opaque agent handle (a NIF resource freed by GC). 95 """ 96 def login(session_path, identifier, password, appview \\ "", dedup_path \\ ""), 97 do: 98 :rocksky.agent_login( 99 to_bin(session_path), 100 to_bin(identifier), 101 to_bin(password), 102 to_bin(appview), 103 to_bin(dedup_path) 104 ) 105 106 @doc "Scrobble a play (fans out to artist/album/song/scrobble). Returns the URIs." 107 def scrobble(agent, track), do: :rocksky.agent_scrobble(agent, track) 108 109 @doc """ 110 Scrobble from just a title + artist (album optional): resolve full metadata 111 via matchSong, then fan out. `input` is a map with camelCase string keys: 112 required `"title"`/`"artist"`; optional `"album"`, `"mbId"`, `"isrc"` (match 113 anchors) and `"timestamp"` (scrobbled-at Unix seconds, default now). 114 115 Rocksky.scrobble_match(agent, %{"title" => "Chaser", "artist" => "Calibro 35"}) 116 """ 117 def scrobble_match(agent, input) when is_map(input), 118 do: :rocksky.agent_scrobble_match(agent, input) 119 120 @doc "Download the caller's repo and (re)build the local dedup index (needs a dedup_path at login)." 121 def sync_repo(agent), do: :rocksky.agent_sync_repo(agent) 122 123 @doc "Keep the local dedup index hydrated from Jetstream in the background." 124 def hydrate_from_jetstream(agent), do: :rocksky.agent_hydrate_from_jetstream(agent) 125 126 @doc "Like a record by strong reference." 127 def like(agent, uri, cid), do: :rocksky.agent_like(agent, to_bin(uri), to_bin(cid)) 128 129 @doc "Follow an account by DID." 130 def follow(agent, did), do: :rocksky.agent_follow(agent, to_bin(did)) 131 132 @doc "Post a shout on a subject." 133 def shout(agent, subject_uri, subject_cid, message), 134 do: :rocksky.agent_shout(agent, to_bin(subject_uri), to_bin(subject_cid), to_bin(message)) 135 136 @doc """ 137 Post a shout with an optional GIF/sticker/clip. Pass at least one of `message` 138 / `gif`. `gif` is a map (`"url"` required, plus `"previewUrl"`, `"alt"`, 139 `"width"`, `"height"`) or `nil`. 140 """ 141 def shout_with_gif(agent, subject_uri, subject_cid, message, gif \\ nil), 142 do: 143 :rocksky.agent_shout_with_gif( 144 agent, 145 to_bin(subject_uri), 146 to_bin(subject_cid), 147 to_bin(message), 148 gif_arg(gif) 149 ) 150 151 @doc "Reply to a shout with an optional GIF/sticker/clip (see `shout_with_gif/5`)." 152 def reply_shout_with_gif(agent, subject_uri, subject_cid, parent_uri, parent_cid, message, gif \\ nil), 153 do: 154 :rocksky.agent_reply_shout_with_gif( 155 agent, 156 to_bin(subject_uri), 157 to_bin(subject_cid), 158 to_bin(parent_uri), 159 to_bin(parent_cid), 160 to_bin(message), 161 gif_arg(gif) 162 ) 163 164 @doc "Proactively refresh the session (keep-alive)." 165 def refresh_session(agent), do: :rocksky.agent_refresh_session(agent) 166 167 defp gif_arg(nil), do: :undefined 168 defp gif_arg(gif), do: gif 169 170 defp to_bin(s) when is_binary(s), do: s 171 defp to_bin(s), do: to_string(s) 172end