rocksky 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +58 -5
- data/lib/rocksky/manifest.json +7 -7
- data/lib/rocksky/version.rb +1 -1
- data/lib/rocksky.rb +76 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f5ff00fa4d526c5436fb713d32c4f49f85609263ccf950ea51a2091bec6d8951
|
|
4
|
+
data.tar.gz: 161fb86cda0ae97b7044a10c9d5a249971143d00d6cf27560500199ebfdcfbfa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c279685557ce908beb4d7e763a6b4d3a6fd6e55d51158aa518bdeb70189ecec3b22b2367bd0cdcb61e72439a22f73745159b21d64326a02d49f2f6cec608a26
|
|
7
|
+
data.tar.gz: 8c09668a64234fc5064e50b53e039cbc9ae2d077290cac0dbeb0769f175ae6f24a65f11a7ae039af34d38793dbbb2897283ff23e7978a87e1ce9453d558c5275
|
data/README.md
CHANGED
|
@@ -11,6 +11,12 @@ every Rocksky SDK.
|
|
|
11
11
|
gem install rocksky
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
Or in a Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem "rocksky", "~> 0.5"
|
|
18
|
+
```
|
|
19
|
+
|
|
14
20
|
The gem is pure-Ruby; the native library is fetched from the GitHub release on
|
|
15
21
|
first load and cached (checksum-verified). For a local checkout, build it once:
|
|
16
22
|
|
|
@@ -46,16 +52,63 @@ camelCase keys.
|
|
|
46
52
|
|
|
47
53
|
### Reads — `Rocksky`
|
|
48
54
|
|
|
49
|
-
`profile(actor, base:)`, `scrobbles(actor, limit:, offset:, base:)`,
|
|
55
|
+
Named reads: `profile(actor, base:)`, `scrobbles(actor, limit:, offset:, base:)`,
|
|
50
56
|
`top_tracks(limit:, offset:, base:)`, `global_stats(base:)`. Every read takes an
|
|
51
57
|
optional `base:` to target a custom AppView.
|
|
52
58
|
|
|
59
|
+
**Universal escape hatch** — `Rocksky.get(nsid, params, base: nil, token: nil)`
|
|
60
|
+
reaches the *whole* `app.rocksky.*` read catalog and returns the parsed
|
|
61
|
+
Hash/Array. Pass `token:` to send an `Authorization: Bearer` header for
|
|
62
|
+
auth-gated queries.
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
Rocksky.get("app.rocksky.album.getAlbums", limit: 10)
|
|
66
|
+
Rocksky.get("app.rocksky.album.getAlbumTracks", uri: album_uri)
|
|
67
|
+
Rocksky.get("app.rocksky.graph.getFollows", actor: "alice.bsky.social")
|
|
68
|
+
Rocksky.get("app.rocksky.actor.getActorLovedSongs", actor: "alice.bsky.social")
|
|
69
|
+
Rocksky.get("app.rocksky.stats.getStats")
|
|
70
|
+
Rocksky.get("app.rocksky.charts.getScrobblesChart", token: "…")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Typed date-window charts** — `top_tracks_interval(limit:, offset:, interval:)`
|
|
74
|
+
and `top_artists_interval(...)`. `interval:` is `:all` or one of
|
|
75
|
+
`[:days, n]` / `[:weeks, n]` / `[:months, n]` / `[:years, n]` /
|
|
76
|
+
`[:range, start, end]`.
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
Rocksky.top_tracks_interval(limit: 5, interval: [:days, 7])
|
|
80
|
+
Rocksky.top_artists_interval(limit: 5, interval: :all)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Match** — `Rocksky.match_song(title, artist, mb_id: nil, isrc: nil)` resolves a
|
|
84
|
+
bare title + artist into full canonical metadata.
|
|
85
|
+
|
|
53
86
|
### Writes — `Rocksky::Agent`
|
|
54
87
|
|
|
55
|
-
`Agent.login(session_path, identifier, password, appview:)` → an
|
|
56
|
-
|
|
57
|
-
`
|
|
58
|
-
`
|
|
88
|
+
`Agent.login(session_path, identifier, password, appview:, dedup_path:)` → an
|
|
89
|
+
agent. Pass `dedup_path:` to enable scrobble dedup + realtime hydration (see
|
|
90
|
+
below). Then `scrobble(track)` (fans out to artist/album/song/scrobble),
|
|
91
|
+
`like(uri, cid)`, `follow(did)`, `shout(subject_uri, subject_cid, message)`,
|
|
92
|
+
`refresh_session`, and `close` (release the native handle).
|
|
93
|
+
|
|
94
|
+
**Two scrobble paths** — `scrobble(track)` takes full metadata, while
|
|
95
|
+
`scrobble_match(title, artist, album: nil, mb_id: nil, isrc: nil)` matches a bare
|
|
96
|
+
title + artist first, then writes.
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
agent.scrobble_match("Chaser", "Calibro 35", album: "Jazzploitation")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Dedup + realtime** — with `dedup_path:` set at login, `agent.sync_repo`
|
|
103
|
+
backfills from the PDS repo and `agent.hydrate_from_jetstream` streams live
|
|
104
|
+
updates, both deduped against the on-disk store.
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
agent = Rocksky::Agent.login("session.json", "alice.bsky.social", "app-password",
|
|
108
|
+
dedup_path: "./dedup")
|
|
109
|
+
agent.sync_repo
|
|
110
|
+
agent.hydrate_from_jetstream
|
|
111
|
+
```
|
|
59
112
|
|
|
60
113
|
### Identity hashes
|
|
61
114
|
|
data/lib/rocksky/manifest.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repo": "tsirysndr/rocksky",
|
|
3
|
-
"tag": "bindings-v0.
|
|
3
|
+
"tag": "bindings-v0.2.0",
|
|
4
4
|
"checksums": {
|
|
5
|
-
"aarch64-apple-darwin": "
|
|
6
|
-
"aarch64-linux-gnu": "
|
|
7
|
-
"x86_64-apple-darwin": "
|
|
8
|
-
"x86_64-linux-gnu": "
|
|
9
|
-
"x86_64-unknown-freebsd": "
|
|
10
|
-
"x86_64-unknown-netbsd": "
|
|
5
|
+
"aarch64-apple-darwin": "3fc61d1194d66f58eaea8b82643bbdcd705ab80a626e38975a3c0d66ea14047d",
|
|
6
|
+
"aarch64-linux-gnu": "4e6f003fb0c45eba7a675b81cc76b084dc770333b2d8c676b2123d19e78f89a0",
|
|
7
|
+
"x86_64-apple-darwin": "a90563838920ef3575b1af55062e5f1bddcd124ba0d4b9bd50b5639ab6c4ed4e",
|
|
8
|
+
"x86_64-linux-gnu": "98c2df9ff416fd3f2f0e50e0e48122751ea829f5208f11002ce9fdd85b0fbe5f",
|
|
9
|
+
"x86_64-unknown-freebsd": "5ad9efc806706ba51cb7f1fe0e678eb97e03e2dd218fec9fe7e7ab29e0efcb68",
|
|
10
|
+
"x86_64-unknown-netbsd": "f82db46965ea7872085920d37f4a854f7f882e0efa257df9a11dd3e2f7cebf48"
|
|
11
11
|
}
|
|
12
12
|
}
|
data/lib/rocksky/version.rb
CHANGED
data/lib/rocksky.rb
CHANGED
|
@@ -26,12 +26,19 @@ module Rocksky
|
|
|
26
26
|
"char* rocksky_scrobbles(const char*, const char*, unsigned int, unsigned int)",
|
|
27
27
|
"char* rocksky_top_tracks(const char*, unsigned int, unsigned int)",
|
|
28
28
|
"char* rocksky_global_stats(const char*)",
|
|
29
|
+
"char* rocksky_get(const char*, const char*, const char*, const char*)",
|
|
30
|
+
"char* rocksky_match_song(const char*, const char*, const char*, const char*, const char*)",
|
|
31
|
+
"char* rocksky_top_tracks_interval(const char*, unsigned int, unsigned int, const char*, unsigned int, const char*, const char*)",
|
|
32
|
+
"char* rocksky_top_artists_interval(const char*, unsigned int, unsigned int, const char*, unsigned int, const char*, const char*)",
|
|
29
33
|
"char* rocksky_song_hash(const char*, const char*, const char*)",
|
|
30
34
|
"void rocksky_string_free(void*)",
|
|
31
35
|
"char* rocksky_last_error()",
|
|
32
|
-
"void* rocksky_agent_login(const char*, const char*, const char*, const char*)",
|
|
36
|
+
"void* rocksky_agent_login(const char*, const char*, const char*, const char*, const char*)",
|
|
33
37
|
"void rocksky_agent_free(void*)",
|
|
34
38
|
"char* rocksky_agent_scrobble(void*, const char*)",
|
|
39
|
+
"char* rocksky_agent_scrobble_match(void*, const char*, const char*, const char*, const char*, const char*)",
|
|
40
|
+
"char* rocksky_agent_sync_repo(void*)",
|
|
41
|
+
"char* rocksky_agent_hydrate_from_jetstream(void*)",
|
|
35
42
|
"char* rocksky_agent_like(void*, const char*, const char*)",
|
|
36
43
|
"char* rocksky_agent_follow(void*, const char*)",
|
|
37
44
|
"char* rocksky_agent_shout(void*, const char*, const char*, const char*)",
|
|
@@ -82,6 +89,53 @@ module Rocksky
|
|
|
82
89
|
unwrap(C.rocksky_global_stats(base.to_s))
|
|
83
90
|
end
|
|
84
91
|
|
|
92
|
+
# Universal read escape hatch — call any app.rocksky.* query by nsid. +params+
|
|
93
|
+
# is a hash of string params; the whole read-query catalog is reachable here.
|
|
94
|
+
#
|
|
95
|
+
# Rocksky.get("app.rocksky.album.getAlbum", { uri: uri })
|
|
96
|
+
# Rocksky.get("app.rocksky.charts.getScrobblesChart", { did: did })
|
|
97
|
+
# +token+, when given, is sent as an Authorization: Bearer header — needed for
|
|
98
|
+
# auth-gated queries.
|
|
99
|
+
def self.get(nsid, params = {}, base: nil, token: nil)
|
|
100
|
+
unwrap(C.rocksky_get(base.to_s, nsid, JSON.generate(params), token.to_s))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Resolve full canonical metadata for a bare title + artist (matchSong).
|
|
104
|
+
def self.match_song(title, artist, mb_id: nil, isrc: nil, base: nil)
|
|
105
|
+
unwrap(C.rocksky_match_song(base.to_s, title, artist, mb_id.to_s, isrc.to_s))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Top tracks chart over a typed date window. +interval+ is +:all+, or a pair
|
|
109
|
+
# like +[:days, 7]+ / +[:weeks, 4]+ / +[:months, 1]+ / +[:years, 1]+, or
|
|
110
|
+
# +[:range, start_rfc3339, end_rfc3339]+.
|
|
111
|
+
#
|
|
112
|
+
# Rocksky.top_tracks_interval(limit: 10, interval: [:days, 7])
|
|
113
|
+
def self.top_tracks_interval(limit: 50, offset: 0, interval: :all, base: nil)
|
|
114
|
+
unit, n, s, e = interval_parts(interval)
|
|
115
|
+
unwrap(C.rocksky_top_tracks_interval(base.to_s, limit, offset, unit, n, s, e))
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Top artists chart over a typed date window (see .top_tracks_interval).
|
|
119
|
+
def self.top_artists_interval(limit: 50, offset: 0, interval: :all, base: nil)
|
|
120
|
+
unit, n, s, e = interval_parts(interval)
|
|
121
|
+
unwrap(C.rocksky_top_artists_interval(base.to_s, limit, offset, unit, n, s, e))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Normalize an interval into (unit, n, start, end) for the native call.
|
|
125
|
+
def self.interval_parts(interval)
|
|
126
|
+
case interval
|
|
127
|
+
when :all, nil then ["all", 0, "", ""]
|
|
128
|
+
when Array
|
|
129
|
+
kind, a, b = interval
|
|
130
|
+
return ["range", 0, a.to_s, b.to_s] if kind == :range
|
|
131
|
+
|
|
132
|
+
[kind.to_s, Integer(a), "", ""]
|
|
133
|
+
else
|
|
134
|
+
raise Error, "invalid interval: #{interval.inspect}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
private_class_method :interval_parts
|
|
138
|
+
|
|
85
139
|
# Identity hash — identical across every Rocksky SDK.
|
|
86
140
|
def self.song_hash(title, artist, album)
|
|
87
141
|
take_string(C.rocksky_song_hash(title, artist, album))
|
|
@@ -92,8 +146,10 @@ module Rocksky
|
|
|
92
146
|
# Records are passed as Hashes with camelCase keys (title, artist, album,
|
|
93
147
|
# albumArtist, durationMs, …), matching the wire record shape.
|
|
94
148
|
class Agent
|
|
95
|
-
|
|
96
|
-
|
|
149
|
+
# +dedup_path+ enables the local dedup index (needed for #sync_repo /
|
|
150
|
+
# #hydrate_from_jetstream).
|
|
151
|
+
def self.login(session_path, identifier, password, appview: nil, dedup_path: nil)
|
|
152
|
+
ptr = C.rocksky_agent_login(session_path, identifier, password, appview.to_s, dedup_path.to_s)
|
|
97
153
|
raise Error, (Rocksky.take_string(C.rocksky_last_error()) || "login failed") if ptr.null?
|
|
98
154
|
|
|
99
155
|
new(ptr)
|
|
@@ -108,6 +164,23 @@ module Rocksky
|
|
|
108
164
|
Rocksky.unwrap(C.rocksky_agent_scrobble(@ptr, JSON.generate(track)))
|
|
109
165
|
end
|
|
110
166
|
|
|
167
|
+
# Scrobble from just a title + artist (album optional, plus optional mb_id /
|
|
168
|
+
# isrc anchors): resolve full metadata via matchSong, then fan out.
|
|
169
|
+
def scrobble_match(title, artist, album: nil, mb_id: nil, isrc: nil)
|
|
170
|
+
Rocksky.unwrap(C.rocksky_agent_scrobble_match(@ptr, title, artist, album.to_s, mb_id.to_s, isrc.to_s))
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Download the caller's repo and (re)build the local dedup index (needs a
|
|
174
|
+
# dedup_path at login). Returns the per-collection counts.
|
|
175
|
+
def sync_repo
|
|
176
|
+
Rocksky.unwrap(C.rocksky_agent_sync_repo(@ptr))
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Keep the local dedup index hydrated from Jetstream in the background.
|
|
180
|
+
def hydrate_from_jetstream
|
|
181
|
+
Rocksky.unwrap(C.rocksky_agent_hydrate_from_jetstream(@ptr))
|
|
182
|
+
end
|
|
183
|
+
|
|
111
184
|
def like(uri, cid)
|
|
112
185
|
Rocksky.unwrap(C.rocksky_agent_like(@ptr, uri, cid))
|
|
113
186
|
end
|