diff --git a/api/Get Album.bru b/api/Get Album.bru new file mode 100644 index 0000000..f26370e --- /dev/null +++ b/api/Get Album.bru @@ -0,0 +1,22 @@ +meta { + name: Get Album + type: grpc + seq: 9 +} + +grpc { + url: localhost:3000 + method: /music_agregator.v1.MusicAgregatorService/GetAlbum + body: grpc + auth: inherit + methodType: unary +} + +body:grpc { + name: message 1 + content: ''' + { + "album_id": "1d51e4a7-1a8b-4160-bd08-1aee658a991a" + } + ''' +} diff --git a/api/Get Artists.bru b/api/Get Artists.bru new file mode 100644 index 0000000..6b275aa --- /dev/null +++ b/api/Get Artists.bru @@ -0,0 +1,20 @@ +meta { + name: Get Artists + type: grpc + seq: 7 +} + +grpc { + url: localhost:3000 + method: /music_agregator.v1.MusicAgregatorService/GetArtists + body: grpc + auth: inherit + methodType: unary +} + +body:grpc { + name: message 1 + content: ''' + {} + ''' +} diff --git a/docs/MonitorAlbum Happy Path.svg b/docs/MonitorAlbum Happy Path.svg new file mode 100644 index 0000000..b66fea1 --- /dev/null +++ b/docs/MonitorAlbum Happy Path.svg @@ -0,0 +1 @@ +ClientgRPC ServerMusicAgregatorServiceMetadataServicemetadata-agregatorPostgreSQLIndexerServiceMagnetResolverTorrentClientRiver QueuePollDownloadWorkerClientClientgRPC ServergRPC ServerMusicAgregatorServiceMusicAgregatorServiceMetadataServiceMetadataServicemetadata-agregator(gRPC)metadata-agregator(gRPC)PostgreSQLPostgreSQLIndexerService(Jackett)IndexerService(Jackett)MagnetResolverMagnetResolverTorrentClient(qBittorrent)TorrentClient(qBittorrent)River QueueRiver QueuePollDownloadWorkerPollDownloadWorker1. Fetch Album MetadataMonitorAlbum(album_id, quality, tracker)MonitorAlbum(ctx, req)GetAlbum(album_id)GetAlbum(id)Album (title, artists, genres, ...)albums.GetByExternalID(external_id)Check if album already persistednot foundartists.Create(artist, state=monitored)Upsert artistnever downgradesmonitored/excludedalbums.Create(album, state=monitored)Upsert albumnever downgradesmonitored/excludedAlbum2. Set Monitor Statealbums.GetByExternalID(external_id)dbAlbumalbums.SetMonitorState(id, monitored)Explicitly markalbum as monitored3. Check If Already Owneddownloads.HasAlbumInQuality(album_id, format, quality)false (not owned)4. Search IndexersSearch(artist + album title, tracker)Jackett API/api/v2.0/indexers/all/resultsSearchResponse (N items)5. Parse & Resolve Releasesloop[for each search result (with download link & seeders > 0)]alt[magnet link]Extract: format, bitDepth, sampleRate,source, trackCount, coverArt, cueSheet, ripLogResolve(magnet_uri)DHT lookup, 30s timeout15s early exit if peersbut none activetorrent metadata (files, hash, size)ParseTorrent(torrentData, album)[HTTP torrent link]downloadTorrentData(url)ParseTorrent(torrentData, album)6. Filter & Select BestfilterByQuality(parsed, quality)Match LOSSLESS/LOSSY/UNSPECIFIEDagainst release formatselectBestRelease(filtered)Highest seeder count wins7. Add to Torrent ClientFind(hash)not foundalt[magnet link]AddMagnet(magnet_uri)[torrent file]AddTorrent(file)OK8. Persist Torrent & Downloadtorrents.Create(torrent)Upsert on info_hashupdates seeders/peerstorrents.GetByInfoHash(hash)savedTorrent (with DB id)downloads.GetActiveByTorrentID(torrent_id)not found (no active download)downloads.Create(download)state = "downloading"format, quality, qbit_hashdownload (with DB id)9. Schedule Download PollInsert(PollDownloadArgs)download_id, torrent_hashcheck_interval = 30sscheduled_at = now + 30sjob scheduled10. Build & Return Responsealbums.GetByExternalID(external_id)dbAlbum (refreshed)downloads.GetByAlbumID(album_id)downloads (with state)artists.GetByExternalID(artist_external_id)dbArtistMonitorAlbumResponsealbum: id, title, monitor_state=monitored,download: state, format, qualityartist: id, name, monitor_staterelease: hash, format, seeders, tracksMonitorAlbumResponse11. Async: Download Polling (River Worker)Work(PollDownloadArgs)Find(hash)TorrentInfo (progress, state, path)alt[progress < 100%]Insert(PollDownloadArgs)Reschedule after check_interval[progress == 100%]downloads.SetCompleted(id, save_path)scanAndHashFiles(content_path)Walk directory, identify audio files(.flac, .mp3, .aac, ...)SHA-256 hash each filedownload_files.CreateBatch(files)file_path, file_size, file_type,sha256_hash, verified_at \ No newline at end of file