From 42818c51c1de542943e254280ef4bc91150ef715 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Thu, 4 Jun 2026 20:44:24 +0000 Subject: [PATCH] feat(rocksky): Update configuration and document new token --- config/rocksky.json.example | 4 +- .../docs/configuration/clients/rocksky.mdx | 37 ++++++++++++------- .../infrastructure/config/client/rocksky.ts | 2 +- src/backend/scrobblers/ScrobbleClients.ts | 1 + src/backend/sources/RockskySource.ts | 13 +++++++ 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/config/rocksky.json.example b/config/rocksky.json.example index ead4f3bb..cb932464 100644 --- a/config/rocksky.json.example +++ b/config/rocksky.json.example @@ -4,7 +4,7 @@ "name": "FoxxMD Rocksky Client", "configureAs": "client", "data": { - "key": "7cdr86vis3mpq5b1pi01md0hkm7ykzzxjy81r", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiJkaWQ6cGxjOng0NjVwZmtyeW5zaDZ...", "handle": "alice.bsky.social" } }, @@ -13,7 +13,7 @@ "name": "FoxxMD Rocksky Source", "configureAs": "source", "data": { - "key": "e4xwktm7jxm607x8el1fcda30eu14dzb64h3j", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiJkaWQ6cGxjOng0NjVwZmtyeW5zaDZ...", "handle": "alice.bsky.social" } } diff --git a/docsite/docs/configuration/clients/rocksky.mdx b/docsite/docs/configuration/clients/rocksky.mdx index 61fca2ef..1f38d965 100644 --- a/docsite/docs/configuration/clients/rocksky.mdx +++ b/docsite/docs/configuration/clients/rocksky.mdx @@ -23,13 +23,13 @@ To monitor and re-scrobble activity **from** Rocksky create a [Rocksky (Source)] - + The default Bluesky PDS is **public**, meaning your scrobbles are also public (read-only). This isn't any different than using Last.fm or Listenbrainz, in terms of privacy. - + Rocksky **does not guarantee** that every scrobble you send will be persisted. Rocksky's design goal is to store scrobbles with **metdata-complete, 3rd party verifiable track information** so that it can be a metadata-rich discovery platform, rather than an exhaustive scrobble data source-of-truth. @@ -41,16 +41,10 @@ If you need your scrobbles to be 100% captured then you should scrobble to an *a ## Setup -You will need a [Bluesky](https://bsky.app/) account to use Rocksky. +You will need a [Bluesky](https://bsky.app/), or other [ATmosphere](https://atproto.brussels/about-the-atmosphere), account to use Rocksky. -:::note - -Usage is adapted from [Rocksky docs](https://docs.rocksky.app/migrating-to-rocksky-scrobble-api-957839m0) on [docs.rocksky.app](https://docs.rocksky.app) - -::: - -* Navigate to [rocksky.app](https://rocksky.app/) and sign up/logn using your Bluesky account -* Then, navigate to the [RockSky developer dashboard](https://rocksky.app/apikeys) and obtain an API Key +* Navigate to [rocksky.app](https://rocksky.app/) and sign up/logn using your ATmosphere account +* Then, navigate to the [Access Tokens](https://rocksky.app/access-tokens) in the Rocksky settings dropdown, and create a new token ## Configuration @@ -64,11 +58,28 @@ The handle used with multi-scrobbler should be your **full** ATProto handle, inc If you do not include a TLD then multi-scrobbler will automatically append `.bsky.social` to your handle value. + + +In < 0.14.1, Multi-Scrobber used Rocksky's API Appication "API Key" for communication with a Listenbrainz-compatible API from Rocksky. + +Going forward, this should be replaced with the official guidance in the [Setup](#setup) section above: use an **Access Token**. This uses the native Rocksky API which has more functionality. + +If your configuration is using either + +* (File/AIO) `'key': ...` +* (ENV) `ROCKSKY_KEY` + +you should redo the [Setup](#setup) modify your configuration to use an Access Token instead. + +Keys are now **deprecated** and functionality for them will be removed in a future version of Multi-Scrobbler. + + + | Environmental Variable | Required? | Default | Description | | :--------------------- | --------- | ------- | ----------------------------------------------------------------------------------- | - | `ROCKSKY_ID` | Yes | | A unique ID | + | `ROCKSKY_ID` | Yes | | A unique ID used in MS | | `ROCKSKY_HANDLE` | Yes | | Your **full** ATProto handle. For Bluesky account this is like `myUser.bsky.social` | - | `ROCKSKY_KEY` | Yes | | API Key obtained from Rocksky developer dashboard | + | `ROCKSKY_TOKEN` | Yes | | Access Token obtained from Rocksky | | `ROCKSKY_NAME` | No | | A vanity name different than ID | \ No newline at end of file diff --git a/src/backend/common/infrastructure/config/client/rocksky.ts b/src/backend/common/infrastructure/config/client/rocksky.ts index 0dff523b..a1576919 100644 --- a/src/backend/common/infrastructure/config/client/rocksky.ts +++ b/src/backend/common/infrastructure/config/client/rocksky.ts @@ -8,7 +8,7 @@ export interface RockSkyData extends RequestRetryOptions{ * * @examples ["6794186bf-1157-4de6-80e5-uvb411f3ea2b"] * */ - key: string + key?: string /** * Access Token generated from https://rocksky.app/access-tokens in Rocksky for your account diff --git a/src/backend/scrobblers/ScrobbleClients.ts b/src/backend/scrobblers/ScrobbleClients.ts index aa6e741a..f58478fc 100644 --- a/src/backend/scrobblers/ScrobbleClients.ts +++ b/src/backend/scrobblers/ScrobbleClients.ts @@ -296,6 +296,7 @@ export default class ScrobbleClients { case 'rocksky': { const data: RockSkyData = removeUndefinedKeys({ key: process.env.ROCKSKY_KEY, + token: process.env.ROCKSKY_TOKEN, handle: process.env.ROCKSKY_HANDLE }, false); const p = getCommonComponentEnvConfig('ROCKSKY'); diff --git a/src/backend/sources/RockskySource.ts b/src/backend/sources/RockskySource.ts index ef397bb2..4bc2d952 100644 --- a/src/backend/sources/RockskySource.ts +++ b/src/backend/sources/RockskySource.ts @@ -37,6 +37,19 @@ export default class RockskySource extends MemorySource { static formatPlayObj(obj: any, options: FormatPlayObjectOptions = {}){ return RockSkyApiClient.formatPlayObj(obj, options); } + protected async doBuildInitData(): Promise { + const { + data: { + key, + token, + } = {} + } = this.config; + if (key === undefined && token === undefined) { + throw new Error('Must provide an API Key or Access Token'); + } + return true; + } + protected async doCheckConnection(): Promise { await this.api.testConnection(); return true;