revert(purchases): remove mock FastAPI server from repository
cx
This commit is contained in:
1 parent
415a9d93f3
commit
861a9e0311
3 files changed
-727
No files matched your search
@@ -1,593 +0,0 @@
|
||||
"""Mock purchase data — Qobuz-shaped responses for UI prototyping."""
|
||||
|
||||
MOCK_ALBUMS = [
|
||||
{
|
||||
"id": "album-001",
|
||||
"title": "Wish You Were Here",
|
||||
"artist": {"id": 36819, "name": "Pink Floyd"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=WYWH",
|
||||
"large": "https://via.placeholder.com/600?text=WYWH",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=WYWH",
|
||||
},
|
||||
"release_date_original": "1975-09-12",
|
||||
"label": {"id": 1, "name": "Harvest"},
|
||||
"genre": {"id": 10, "name": "Rock"},
|
||||
"tracks_count": 5,
|
||||
"duration": 2580,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"downloadable": True,
|
||||
"downloaded": True,
|
||||
"purchased_at": "2026-01-15T10:30:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 5,
|
||||
"items": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "Shine On You Crazy Diamond (Parts I-V)",
|
||||
"track_number": 1,
|
||||
"media_number": 1,
|
||||
"duration": 810,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"title": "Welcome to the Machine",
|
||||
"track_number": 2,
|
||||
"media_number": 1,
|
||||
"duration": 447,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 103,
|
||||
"title": "Have a Cigar",
|
||||
"track_number": 3,
|
||||
"media_number": 1,
|
||||
"duration": 308,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 104,
|
||||
"title": "Wish You Were Here",
|
||||
"track_number": 4,
|
||||
"media_number": 1,
|
||||
"duration": 334,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 105,
|
||||
"title": "Shine On You Crazy Diamond (Parts VI-IX)",
|
||||
"track_number": 5,
|
||||
"media_number": 1,
|
||||
"duration": 751,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-002",
|
||||
"title": "Kind of Blue",
|
||||
"artist": {"id": 26577, "name": "Miles Davis"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=KoB",
|
||||
"large": "https://via.placeholder.com/600?text=KoB",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=KoB",
|
||||
},
|
||||
"release_date_original": "1959-08-17",
|
||||
"label": {"id": 2, "name": "Columbia"},
|
||||
"genre": {"id": 20, "name": "Jazz"},
|
||||
"tracks_count": 5,
|
||||
"duration": 2760,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"downloadable": True,
|
||||
"downloaded": True,
|
||||
"purchased_at": "2026-01-20T14:00:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 5,
|
||||
"items": [
|
||||
{
|
||||
"id": 201,
|
||||
"title": "So What",
|
||||
"track_number": 1,
|
||||
"media_number": 1,
|
||||
"duration": 562,
|
||||
"performer": {"id": 26577, "name": "Miles Davis"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 202,
|
||||
"title": "Freddie Freeloader",
|
||||
"track_number": 2,
|
||||
"media_number": 1,
|
||||
"duration": 586,
|
||||
"performer": {"id": 26577, "name": "Miles Davis"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 203,
|
||||
"title": "Blue in Green",
|
||||
"track_number": 3,
|
||||
"media_number": 1,
|
||||
"duration": 327,
|
||||
"performer": {"id": 26577, "name": "Miles Davis"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 204,
|
||||
"title": "All Blues",
|
||||
"track_number": 4,
|
||||
"media_number": 1,
|
||||
"duration": 695,
|
||||
"performer": {"id": 26577, "name": "Miles Davis"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 205,
|
||||
"title": "Flamenco Sketches",
|
||||
"track_number": 5,
|
||||
"media_number": 1,
|
||||
"duration": 566,
|
||||
"performer": {"id": 26577, "name": "Miles Davis"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-003",
|
||||
"title": "In the Court of the Crimson King",
|
||||
"artist": {"id": 18290, "name": "King Crimson"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=ITCOTCK",
|
||||
"large": "https://via.placeholder.com/600?text=ITCOTCK",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=ITCOTCK",
|
||||
},
|
||||
"release_date_original": "1969-10-10",
|
||||
"label": {"id": 3, "name": "Island"},
|
||||
"genre": {"id": 11, "name": "Progressive Rock"},
|
||||
"tracks_count": 5,
|
||||
"duration": 2630,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"downloadable": True,
|
||||
"purchased_at": "2026-02-01T08:15:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 5,
|
||||
"items": [
|
||||
{
|
||||
"id": 301,
|
||||
"title": "21st Century Schizoid Man",
|
||||
"track_number": 1,
|
||||
"media_number": 1,
|
||||
"duration": 442,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 302,
|
||||
"title": "I Talk to the Wind",
|
||||
"track_number": 2,
|
||||
"media_number": 1,
|
||||
"duration": 363,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 303,
|
||||
"title": "Epitaph",
|
||||
"track_number": 3,
|
||||
"media_number": 1,
|
||||
"duration": 527,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 304,
|
||||
"title": "Moonchild",
|
||||
"track_number": 4,
|
||||
"media_number": 1,
|
||||
"duration": 732,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
{
|
||||
"id": 305,
|
||||
"title": "The Court of the Crimson King",
|
||||
"track_number": 5,
|
||||
"media_number": 1,
|
||||
"duration": 566,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-004",
|
||||
"title": "OK Computer",
|
||||
"artist": {"id": 12345, "name": "Radiohead"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=OKC",
|
||||
"large": "https://via.placeholder.com/600?text=OKC",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=OKC",
|
||||
},
|
||||
"release_date_original": "1997-06-16",
|
||||
"label": {"id": 4, "name": "Parlophone"},
|
||||
"genre": {"id": 12, "name": "Alternative Rock"},
|
||||
"tracks_count": 12,
|
||||
"duration": 3218,
|
||||
"hires": False,
|
||||
"maximum_bit_depth": 16,
|
||||
"maximum_sampling_rate": 44.1,
|
||||
"downloadable": True,
|
||||
"purchased_at": "2025-12-25T09:00:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 12,
|
||||
"items": [
|
||||
{"id": 401, "title": "Airbag", "track_number": 1, "media_number": 1, "duration": 278, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 402, "title": "Paranoid Android", "track_number": 2, "media_number": 1, "duration": 384, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 403, "title": "Subterranean Homesick Alien", "track_number": 3, "media_number": 1, "duration": 264, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 404, "title": "Exit Music (For a Film)", "track_number": 4, "media_number": 1, "duration": 261, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 405, "title": "Let Down", "track_number": 5, "media_number": 1, "duration": 294, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 406, "title": "Karma Police", "track_number": 6, "media_number": 1, "duration": 264, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 407, "title": "Fitter Happier", "track_number": 7, "media_number": 1, "duration": 117, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 408, "title": "Electioneering", "track_number": 8, "media_number": 1, "duration": 234, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 409, "title": "Climbing Up the Walls", "track_number": 9, "media_number": 1, "duration": 282, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 410, "title": "No Surprises", "track_number": 10, "media_number": 1, "duration": 229, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 411, "title": "Lucky", "track_number": 11, "media_number": 1, "duration": 261, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
{"id": 412, "title": "The Tourist", "track_number": 12, "media_number": 1, "duration": 324, "performer": {"id": 12345, "name": "Radiohead"}, "hires": False, "maximum_bit_depth": 16, "maximum_sampling_rate": 44.1, "streamable": True},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-005",
|
||||
"title": "A Love Supreme",
|
||||
"artist": {"id": 44321, "name": "John Coltrane"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=ALS",
|
||||
"large": "https://via.placeholder.com/600?text=ALS",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=ALS",
|
||||
},
|
||||
"release_date_original": "1965-02-01",
|
||||
"label": {"id": 5, "name": "Impulse!"},
|
||||
"genre": {"id": 20, "name": "Jazz"},
|
||||
"tracks_count": 4,
|
||||
"duration": 1980,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"downloadable": True,
|
||||
"purchased_at": "2026-02-10T16:45:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 4,
|
||||
"items": [
|
||||
{"id": 501, "title": "Acknowledgement", "track_number": 1, "media_number": 1, "duration": 480, "performer": {"id": 44321, "name": "John Coltrane"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 502, "title": "Resolution", "track_number": 2, "media_number": 1, "duration": 442, "performer": {"id": 44321, "name": "John Coltrane"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 503, "title": "Pursuance", "track_number": 3, "media_number": 1, "duration": 617, "performer": {"id": 44321, "name": "John Coltrane"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 504, "title": "Psalm", "track_number": 4, "media_number": 1, "duration": 441, "performer": {"id": 44321, "name": "John Coltrane"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-006",
|
||||
"title": "Buena Vista Social Club",
|
||||
"artist": {"id": 55432, "name": "Buena Vista Social Club"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=BVSC",
|
||||
"large": "https://via.placeholder.com/600?text=BVSC",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=BVSC",
|
||||
},
|
||||
"release_date_original": "1997-09-16",
|
||||
"label": {"id": 6, "name": "World Circuit"},
|
||||
"genre": {"id": 30, "name": "Latin"},
|
||||
"tracks_count": 14,
|
||||
"duration": 3600,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"downloadable": True,
|
||||
"purchased_at": "2026-02-14T12:00:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 14,
|
||||
"items": [
|
||||
{"id": 601, "title": "Chan Chan", "track_number": 1, "media_number": 1, "duration": 274, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 602, "title": "De Camino a la Vereda", "track_number": 2, "media_number": 1, "duration": 227, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 603, "title": "El Cuarto de Tula", "track_number": 3, "media_number": 1, "duration": 444, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 604, "title": "Pueblo Nuevo", "track_number": 4, "media_number": 1, "duration": 207, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 605, "title": "Dos Gardenias", "track_number": 5, "media_number": 1, "duration": 205, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 606, "title": "Y Tu Que Has Hecho?", "track_number": 6, "media_number": 1, "duration": 195, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 607, "title": "Veinte Anos", "track_number": 7, "media_number": 1, "duration": 194, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 608, "title": "El Carretero", "track_number": 8, "media_number": 1, "duration": 207, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 609, "title": "Candela", "track_number": 9, "media_number": 1, "duration": 306, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 610, "title": "Amor de Loca Juventud", "track_number": 10, "media_number": 1, "duration": 178, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 611, "title": "Orgullecida", "track_number": 11, "media_number": 1, "duration": 179, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 612, "title": "Murmullo", "track_number": 12, "media_number": 1, "duration": 144, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 613, "title": "Buena Vista Social Club", "track_number": 13, "media_number": 1, "duration": 297, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 614, "title": "La Bayamesa", "track_number": 14, "media_number": 1, "duration": 343, "performer": {"id": 55432, "name": "Buena Vista Social Club"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-007",
|
||||
"title": "The Wall",
|
||||
"artist": {"id": 36819, "name": "Pink Floyd"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=Wall",
|
||||
"large": "https://via.placeholder.com/600?text=Wall",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=Wall",
|
||||
},
|
||||
"release_date_original": "1979-11-30",
|
||||
"label": {"id": 1, "name": "Harvest"},
|
||||
"genre": {"id": 10, "name": "Rock"},
|
||||
"tracks_count": 26,
|
||||
"duration": 4860,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"downloadable": False, # Unavailable — for gray-out test
|
||||
"purchased_at": "2025-11-01T18:00:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 26,
|
||||
"items": [
|
||||
{"id": 701, "title": "In the Flesh?", "track_number": 1, "media_number": 1, "duration": 199, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 702, "title": "The Thin Ice", "track_number": 2, "media_number": 1, "duration": 146, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 703, "title": "Another Brick in the Wall, Pt. 1", "track_number": 3, "media_number": 1, "duration": 200, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 704, "title": "The Happiest Days of Our Lives", "track_number": 4, "media_number": 1, "duration": 106, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 705, "title": "Another Brick in the Wall, Pt. 2", "track_number": 5, "media_number": 1, "duration": 238, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 706, "title": "Mother", "track_number": 6, "media_number": 1, "duration": 323, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 707, "title": "Goodbye Blue Sky", "track_number": 7, "media_number": 1, "duration": 170, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 708, "title": "Empty Spaces", "track_number": 8, "media_number": 1, "duration": 129, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 709, "title": "Young Lust", "track_number": 9, "media_number": 1, "duration": 198, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 710, "title": "One of My Turns", "track_number": 10, "media_number": 1, "duration": 213, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 711, "title": "Don't Leave Me Now", "track_number": 11, "media_number": 1, "duration": 254, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 712, "title": "Another Brick in the Wall, Pt. 3", "track_number": 12, "media_number": 1, "duration": 74, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 713, "title": "Goodbye Cruel World", "track_number": 13, "media_number": 1, "duration": 67, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
# Disc 2
|
||||
{"id": 714, "title": "Hey You", "track_number": 1, "media_number": 2, "duration": 282, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 715, "title": "Is There Anybody Out There?", "track_number": 2, "media_number": 2, "duration": 161, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 716, "title": "Nobody Home", "track_number": 3, "media_number": 2, "duration": 202, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 717, "title": "Vera", "track_number": 4, "media_number": 2, "duration": 95, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 718, "title": "Bring the Boys Back Home", "track_number": 5, "media_number": 2, "duration": 86, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 719, "title": "Comfortably Numb", "track_number": 6, "media_number": 2, "duration": 382, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 720, "title": "The Show Must Go On", "track_number": 7, "media_number": 2, "duration": 97, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 721, "title": "In the Flesh", "track_number": 8, "media_number": 2, "duration": 256, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 722, "title": "Run Like Hell", "track_number": 9, "media_number": 2, "duration": 252, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 723, "title": "Waiting for the Worms", "track_number": 10, "media_number": 2, "duration": 240, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 724, "title": "Stop", "track_number": 11, "media_number": 2, "duration": 30, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 725, "title": "The Trial", "track_number": 12, "media_number": 2, "duration": 311, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
{"id": 726, "title": "Outside the Wall", "track_number": 13, "media_number": 2, "duration": 105, "performer": {"id": 36819, "name": "Pink Floyd"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 192.0, "streamable": True},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "album-008",
|
||||
"title": "Mezzanine",
|
||||
"artist": {"id": 66789, "name": "Massive Attack"},
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=Mezz",
|
||||
"large": "https://via.placeholder.com/600?text=Mezz",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=Mezz",
|
||||
},
|
||||
"release_date_original": "1998-04-20",
|
||||
"label": {"id": 7, "name": "Virgin"},
|
||||
"genre": {"id": 13, "name": "Electronic"},
|
||||
"tracks_count": 11,
|
||||
"duration": 3780,
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"downloadable": True,
|
||||
"purchased_at": "2026-02-16T20:00:00Z",
|
||||
"tracks": {
|
||||
"offset": 0,
|
||||
"limit": 50,
|
||||
"total": 11,
|
||||
"items": [
|
||||
{"id": 801, "title": "Angel", "track_number": 1, "media_number": 1, "duration": 379, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 802, "title": "Risingson", "track_number": 2, "media_number": 1, "duration": 298, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 803, "title": "Teardrop", "track_number": 3, "media_number": 1, "duration": 328, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 804, "title": "Inertia Creeps", "track_number": 4, "media_number": 1, "duration": 368, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 805, "title": "Exchange", "track_number": 5, "media_number": 1, "duration": 246, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 806, "title": "Dissolved Girl", "track_number": 6, "media_number": 1, "duration": 340, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 807, "title": "Man Next Door", "track_number": 7, "media_number": 1, "duration": 363, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 808, "title": "Black Milk", "track_number": 8, "media_number": 1, "duration": 376, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 809, "title": "Mezzanine", "track_number": 9, "media_number": 1, "duration": 359, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 810, "title": "Group Four", "track_number": 10, "media_number": 1, "duration": 489, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
{"id": 811, "title": "(Exchange)", "track_number": 11, "media_number": 1, "duration": 234, "performer": {"id": 66789, "name": "Massive Attack"}, "hires": True, "maximum_bit_depth": 24, "maximum_sampling_rate": 96.0, "streamable": True},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# Individual tracks purchased outside of albums
|
||||
MOCK_INDIVIDUAL_TRACKS = [
|
||||
{
|
||||
"id": 9001,
|
||||
"title": "Comfortably Numb",
|
||||
"track_number": 6,
|
||||
"media_number": 2,
|
||||
"duration": 382,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"album": {
|
||||
"id": "album-007",
|
||||
"title": "The Wall",
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=Wall",
|
||||
"large": "https://via.placeholder.com/600?text=Wall",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=Wall",
|
||||
},
|
||||
},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
"purchased_at": "2026-02-15T11:00:00Z",
|
||||
},
|
||||
{
|
||||
"id": 9002,
|
||||
"title": "Money",
|
||||
"track_number": 6,
|
||||
"media_number": 1,
|
||||
"duration": 382,
|
||||
"performer": {"id": 36819, "name": "Pink Floyd"},
|
||||
"album": {
|
||||
"id": "album-dsotm",
|
||||
"title": "The Dark Side of the Moon",
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=DSotM",
|
||||
"large": "https://via.placeholder.com/600?text=DSotM",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=DSotM",
|
||||
},
|
||||
},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 192.0,
|
||||
"streamable": True,
|
||||
"downloaded": True,
|
||||
"purchased_at": "2026-02-12T09:30:00Z",
|
||||
},
|
||||
{
|
||||
"id": 9003,
|
||||
"title": "Starless",
|
||||
"track_number": 8,
|
||||
"media_number": 1,
|
||||
"duration": 726,
|
||||
"performer": {"id": 18290, "name": "King Crimson"},
|
||||
"album": {
|
||||
"id": "album-rtta",
|
||||
"title": "Red",
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=Red",
|
||||
"large": "https://via.placeholder.com/600?text=Red",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=Red",
|
||||
},
|
||||
},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
"purchased_at": "2026-02-08T14:20:00Z",
|
||||
},
|
||||
{
|
||||
"id": 9004,
|
||||
"title": "Teardrop",
|
||||
"track_number": 3,
|
||||
"media_number": 1,
|
||||
"duration": 328,
|
||||
"performer": {"id": 66789, "name": "Massive Attack"},
|
||||
"album": {
|
||||
"id": "album-008",
|
||||
"title": "Mezzanine",
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=Mezz",
|
||||
"large": "https://via.placeholder.com/600?text=Mezz",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=Mezz",
|
||||
},
|
||||
},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
"downloaded": True,
|
||||
"purchased_at": "2026-01-28T17:45:00Z",
|
||||
},
|
||||
{
|
||||
"id": 9005,
|
||||
"title": "Chan Chan",
|
||||
"track_number": 1,
|
||||
"media_number": 1,
|
||||
"duration": 274,
|
||||
"performer": {"id": 55432, "name": "Buena Vista Social Club"},
|
||||
"album": {
|
||||
"id": "album-006",
|
||||
"title": "Buena Vista Social Club",
|
||||
"image": {
|
||||
"small": "https://via.placeholder.com/150?text=BVSC",
|
||||
"large": "https://via.placeholder.com/600?text=BVSC",
|
||||
"thumbnail": "https://via.placeholder.com/50?text=BVSC",
|
||||
},
|
||||
},
|
||||
"hires": True,
|
||||
"maximum_bit_depth": 24,
|
||||
"maximum_sampling_rate": 96.0,
|
||||
"streamable": True,
|
||||
"purchased_at": "2026-01-05T08:00:00Z",
|
||||
},
|
||||
]
|
||||
|
||||
MOCK_FORMATS = [
|
||||
{"id": 27, "label": "FLAC Hi-Res 24-bit / 192 kHz", "bit_depth": 24, "sampling_rate": 192.0},
|
||||
{"id": 7, "label": "FLAC Hi-Res 24-bit / 96 kHz", "bit_depth": 24, "sampling_rate": 96.0},
|
||||
{"id": 6, "label": "FLAC CD 16-bit / 44.1 kHz", "bit_depth": 16, "sampling_rate": 44.1},
|
||||
{"id": 5, "label": "MP3 320 kbps", "bit_depth": None, "sampling_rate": None},
|
||||
]
|
||||
@@ -1,131 +0,0 @@
|
||||
"""Mock Purchases API — Qobuz-shaped responses for UI prototyping."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import StreamingResponse
|
||||
|
||||
from data import MOCK_ALBUMS, MOCK_INDIVIDUAL_TRACKS, MOCK_FORMATS
|
||||
|
||||
app = FastAPI(title="QBZ Mock Purchases API")
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:1420", "http://localhost:1421"],
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
ALBUMS_BY_ID = {a["id"]: a for a in MOCK_ALBUMS}
|
||||
|
||||
|
||||
def paginate(items: list, limit: int, offset: int) -> dict:
|
||||
return {
|
||||
"offset": offset,
|
||||
"limit": limit,
|
||||
"total": len(items),
|
||||
"items": items[offset : offset + limit],
|
||||
}
|
||||
|
||||
|
||||
@app.get("/purchases")
|
||||
def get_purchases(limit: int = Query(50, ge=1, le=500), offset: int = Query(0, ge=0)):
|
||||
return {
|
||||
"albums": paginate(MOCK_ALBUMS, limit, offset),
|
||||
"tracks": paginate(MOCK_INDIVIDUAL_TRACKS, limit, offset),
|
||||
}
|
||||
|
||||
|
||||
@app.get("/purchases/search")
|
||||
def search_purchases(q: str = Query("", min_length=0)):
|
||||
query = q.lower()
|
||||
if not query:
|
||||
return {
|
||||
"albums": paginate(MOCK_ALBUMS, 50, 0),
|
||||
"tracks": paginate(MOCK_INDIVIDUAL_TRACKS, 50, 0),
|
||||
}
|
||||
|
||||
matched_albums = [
|
||||
a
|
||||
for a in MOCK_ALBUMS
|
||||
if query in a["title"].lower() or query in a["artist"]["name"].lower()
|
||||
]
|
||||
matched_tracks = [
|
||||
t
|
||||
for t in MOCK_INDIVIDUAL_TRACKS
|
||||
if query in t["title"].lower() or query in t["performer"]["name"].lower()
|
||||
]
|
||||
return {
|
||||
"albums": paginate(matched_albums, 50, 0),
|
||||
"tracks": paginate(matched_tracks, 50, 0),
|
||||
}
|
||||
|
||||
|
||||
@app.get("/purchases/album/{album_id}")
|
||||
def get_album_detail(album_id: str):
|
||||
album = ALBUMS_BY_ID.get(album_id)
|
||||
if not album:
|
||||
return {"error": "Album not found"}, 404
|
||||
return album
|
||||
|
||||
|
||||
@app.get("/purchases/formats/{album_id}")
|
||||
def get_formats(album_id: str):
|
||||
album = ALBUMS_BY_ID.get(album_id)
|
||||
if not album:
|
||||
return MOCK_FORMATS
|
||||
max_depth = album.get("maximum_bit_depth", 16)
|
||||
max_rate = album.get("maximum_sampling_rate", 44.1)
|
||||
return [
|
||||
f
|
||||
for f in MOCK_FORMATS
|
||||
if (f["bit_depth"] is None)
|
||||
or (f["bit_depth"] <= max_depth and f["sampling_rate"] <= max_rate)
|
||||
]
|
||||
|
||||
|
||||
async def _download_progress_generator(total_tracks: int, entity_id: str, is_album: bool):
|
||||
"""SSE stream simulating download progress."""
|
||||
for idx in range(total_tracks):
|
||||
total_bytes = 50_000_000 + idx * 10_000_000
|
||||
# Simulate progress in 4 steps per track
|
||||
for step in range(4):
|
||||
progress = {
|
||||
"albumId" if is_album else "trackId": entity_id,
|
||||
"trackIndex": idx,
|
||||
"totalTracks": total_tracks,
|
||||
"bytesDownloaded": int(total_bytes * (step + 1) / 4),
|
||||
"totalBytes": total_bytes,
|
||||
"status": "downloading" if step < 3 else "complete",
|
||||
}
|
||||
yield f"data: {json.dumps(progress)}\n\n"
|
||||
await asyncio.sleep(0.3)
|
||||
|
||||
# Final event
|
||||
yield f"data: {json.dumps({'status': 'complete', 'totalTracks': total_tracks})}\n\n"
|
||||
|
||||
|
||||
@app.post("/purchases/download/album/{album_id}")
|
||||
async def download_album(album_id: str):
|
||||
album = ALBUMS_BY_ID.get(album_id)
|
||||
if not album:
|
||||
return {"error": "Album not found"}, 404
|
||||
if not album.get("downloadable", True):
|
||||
return {"error": "Album not available for download"}, 403
|
||||
|
||||
total = album.get("tracks_count", 1)
|
||||
return StreamingResponse(
|
||||
_download_progress_generator(total, album_id, is_album=True),
|
||||
media_type="text/event-stream",
|
||||
)
|
||||
|
||||
|
||||
@app.post("/purchases/download/track/{track_id}")
|
||||
async def download_track(track_id: int):
|
||||
return StreamingResponse(
|
||||
_download_progress_generator(1, str(track_id), is_album=False),
|
||||
media_type="text/event-stream",
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
fastapi>=0.110.0
|
||||
uvicorn>=0.29.0
|
||||
sse-starlette>=2.0.0
|
||||
Reference in new issue
Block a user