···99- ๐ค Manually scrobble tracks
1010- ๐ ๏ธ Useful developer tools for integrating Rocksky into your workflows
11111212+## Run in development
1313+To run the CLI in development mode, install the dependencies:
1414+1515+```bash
1616+bun install
1717+```
1818+1919+Then, run the CLI with:
2020+2121+```bash
2222+bun run dev --help
2323+```
2424+2525+1226## Usage
13271428```bash
···2943rocksky nowplaying
3044```
31454646+`scrobbles` - Lists all recently scrobbled tracks.
4747+4848+```bash
4949+rocksky scrobbles
5050+```
···33import fs from "fs/promises";
44import os from "os";
55import path from "path";
66-import chalk from "chalk";
7687export async function nowplaying(did?: string) {
98 const tokenPath = path.join(os.homedir(), ".rocksky", "token.json");
···1110 await fs.access(tokenPath);
1211 } catch (err) {
1312 console.error(
1414- `You are not logged in. Please run ${
1515- chalk.greenBright(
1616- "`rocksky login <username>.bsky.social`",
1717- )
1818- } first.`,
1313+ `You are not logged in. Please run ${chalk.greenBright(
1414+ "`rocksky login <username>.bsky.social`"
1515+ )} first.`
1916 );
2017 return;
2118 }
···2421 const { token } = JSON.parse(tokenData);
2522 if (!token) {
2623 console.error(
2727- `You are not logged in. Please run ${
2828- chalk.greenBright(
2929- "`rocksky login <username>.bsky.social`",
3030- )
3131- } first.`,
2424+ `You are not logged in. Please run ${chalk.greenBright(
2525+ "`rocksky login <username>.bsky.social`"
2626+ )} first.`
3227 );
3328 return;
3429 }
···49445045 console.log(
5146 chalk.magenta(
5252- `${nowPlaying.item.name} - ${
5353- nowPlaying.item.artists
5454- .map((a) => a.name)
5555- .join(", ")
5656- }`,
5757- ),
4747+ `${nowPlaying.item.name} - ${nowPlaying.item.artists
4848+ .map((a) => a.name)
4949+ .join(", ")}`
5050+ )
5851 );
5952 console.log(`${nowPlaying.item.album.name}`);
6053 } catch (err) {
6154 console.log(err);
6255 console.error(
6363- `Failed to fetch now playing data. Please check your token and try again.`,
5656+ `Failed to fetch now playing data. Please check your token and try again.`
6457 );
6558 }
6659}
+30
src/cmd/scrobbles.ts
···11+import chalk from "chalk";
22+import { RockskyClient } from "client";
33+import dayjs from "dayjs";
44+import relative from "dayjs/plugin/relativeTime.js";
55+66+dayjs.extend(relative);
77+88+export async function scrobbles(did, { skip, limit }) {
99+ const client = new RockskyClient();
1010+ const scrobbles = await client.scrobbles(did, { skip, limit });
1111+1212+ for (const scrobble of scrobbles) {
1313+ if (did) {
1414+ console.log(
1515+ `${chalk.bold.magenta(scrobble.title)} ${
1616+ scrobble.artist
1717+ } ${chalk.yellow(dayjs(scrobble.created_at + "Z").fromNow())}`
1818+ );
1919+ continue;
2020+ }
2121+ const handle = `@${scrobble.user}`;
2222+ console.log(
2323+ `${chalk.italic.magentaBright(
2424+ handle
2525+ )} is listening to ${chalk.bold.magenta(scrobble.title)} ${
2626+ scrobble.artist
2727+ } ${chalk.yellow(dayjs(scrobble.date).fromNow())}`
2828+ );
2929+ }
3030+}
+9
src/index.ts
···11#!/usr/bin/env node
2233import { nowplaying } from "cmd/nowplaying";
44+import { scrobbles } from "cmd/scrobbles";
45import { whoami } from "cmd/whoami";
56import { Command } from "commander";
67import version from "../package.json" assert { type: "json" };
···3435 )
3536 .description("Get the currently playing track.")
3637 .action(nowplaying);
3838+3939+program
4040+ .command("scrobbles")
4141+ .option("-s, --skip <number>", "Number of scrobbles to skip")
4242+ .option("-l, --limit <number>", "Number of scrobbles to limit")
4343+ .argument("[did]", "The DID or handle of the user to get the scrobbles for.")
4444+ .description("Display recently played tracks.")
4545+ .action(scrobbles);
37463847program.parse(process.argv);