🎧 The official command-line interface for Rocksky — a modern, decentralized music tracking and discovery platform built on the AT Protocol.

implement search command

+104
+19
src/client.ts
··· 100 100 101 101 return response.json(); 102 102 } 103 + 104 + async search(query: string, { size }) { 105 + const response = await fetch( 106 + `${ROCKSKY_API_URL}/search?q=${query}&size=${size}`, 107 + { 108 + method: "GET", 109 + headers: { 110 + Authorization: this.token ? `Bearer ${this.token}` : undefined, 111 + "Content-Type": "application/json", 112 + }, 113 + } 114 + ); 115 + 116 + if (!response.ok) { 117 + throw new Error(`Failed to fetch search data: ${response.statusText}`); 118 + } 119 + 120 + return response.json(); 121 + } 103 122 }
+71
src/cmd/search.ts
··· 1 + import chalk from "chalk"; 2 + import { RockskyClient } from "client"; 3 + 4 + export async function search( 5 + query: string, 6 + { limit = 20, albums = false, artists = false, tracks = false, users = false } 7 + ) { 8 + const client = new RockskyClient(); 9 + const results = await client.search(query, { size: limit }); 10 + if (results.records.length === 0) { 11 + console.log(`No results found for ${chalk.magenta(query)}.`); 12 + return; 13 + } 14 + 15 + // merge all results into one array with type and sort by xata_scrore 16 + let mergedResults = results.records.map((record) => ({ 17 + ...record, 18 + type: record.table, 19 + })); 20 + mergedResults.sort((a, b) => b.xata_score - a.xata_score); 21 + 22 + if (albums) { 23 + mergedResults = mergedResults.filter((record) => record.table === "albums"); 24 + } 25 + 26 + if (artists) { 27 + mergedResults = mergedResults.filter( 28 + (record) => record.table === "artists" 29 + ); 30 + } 31 + 32 + if (tracks) { 33 + mergedResults = mergedResults.filter(({ table }) => table === "tracks"); 34 + } 35 + 36 + if (users) { 37 + mergedResults = mergedResults.filter(({ table }) => table === "users"); 38 + } 39 + 40 + for (const { table, record } of mergedResults) { 41 + if (table === "users") { 42 + console.log( 43 + `${chalk.bold.magenta(record.handle)} ${ 44 + record.display_name 45 + } ${chalk.yellow(`https://rocksky.app/profile/${record.did}`)}` 46 + ); 47 + } 48 + 49 + if (table === "albums") { 50 + const link = record.uri 51 + ? `https://rocksky.app/${record.uri?.split("at://")[1]}` 52 + : ""; 53 + console.log( 54 + `${chalk.bold.magenta(record.title)} ${record.artist} ${chalk.yellow( 55 + link 56 + )}` 57 + ); 58 + } 59 + 60 + if (table === "tracks") { 61 + const link = record.uri 62 + ? `https://rocksky.app/${record.uri?.split("at://")[1]}` 63 + : ""; 64 + console.log( 65 + `${chalk.bold.magenta(record.title)} ${record.artist} ${chalk.yellow( 66 + link 67 + )}` 68 + ); 69 + } 70 + } 71 + }
+14
src/index.ts
··· 2 2 3 3 import { nowplaying } from "cmd/nowplaying"; 4 4 import { scrobbles } from "cmd/scrobbles"; 5 + import { search } from "cmd/search"; 5 6 import { whoami } from "cmd/whoami"; 6 7 import { Command } from "commander"; 7 8 import version from "../package.json" assert { type: "json" }; ··· 43 44 .argument("[did]", "The DID or handle of the user to get the scrobbles for.") 44 45 .description("Display recently played tracks.") 45 46 .action(scrobbles); 47 + 48 + program 49 + .command("search") 50 + .option("-a, --albums", "Search for albums") 51 + .option("-t, --tracks", "Search for tracks") 52 + .option("-u, --users", "Search for users") 53 + .option("-l, --limit <number>", "Number of results to limit") 54 + .argument( 55 + "<query>", 56 + "The search query, e.g., artist, album, title or account" 57 + ) 58 + .description("Search for tracks, albums, or accounts.") 59 + .action(search); 46 60 47 61 program.parse(process.argv);