@audiofool/moondog 0.1.0 → 0.2.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +156 -68
  3. package/contracts/v1/definitions.schema.json +1 -169
  4. package/package.json +7 -23
  5. package/scripts/contract-lib.mjs +0 -7
  6. package/scripts/contract-semantics.mjs +0 -1904
  7. package/scripts/moondog.mjs +285 -74
  8. package/src/core/apple-library-source-status.mjs +0 -16
  9. package/src/core/apple-projection-domain-services.mjs +253 -53
  10. package/src/core/application-update.mjs +320 -0
  11. package/src/core/capability-catalog.mjs +290 -55
  12. package/src/core/listener-avoids.mjs +101 -0
  13. package/src/core/listening-now.mjs +108 -0
  14. package/src/core/listening-profile-domain-services.mjs +189 -41
  15. package/src/core/listening-upkeep.mjs +31 -0
  16. package/src/core/moondog-application.mjs +2115 -107
  17. package/src/core/playback-preferences.mjs +97 -0
  18. package/src/core/spotify-listening-intent.mjs +124 -0
  19. package/src/core/synthetic-domain-services.mjs +24 -3
  20. package/src/core/track-title.mjs +107 -0
  21. package/src/demo/moondog-demo.mjs +4 -22
  22. package/src/i18n/index.mjs +285 -0
  23. package/src/i18n/messages/de.mjs +135 -0
  24. package/src/i18n/messages/en.mjs +136 -0
  25. package/src/i18n/messages/es.mjs +135 -0
  26. package/src/i18n/messages/fr.mjs +135 -0
  27. package/src/i18n/messages/it.mjs +135 -0
  28. package/src/i18n/messages/ja.mjs +135 -0
  29. package/src/i18n/messages/ko.mjs +135 -0
  30. package/src/i18n/messages/pt.mjs +135 -0
  31. package/src/i18n/messages/zh-Hant.mjs +135 -0
  32. package/src/i18n/messages/zh.mjs +135 -0
  33. package/src/i18n/preferences.mjs +34 -0
  34. package/src/i18n/screen/es.mjs +967 -0
  35. package/src/i18n/screen/ja.mjs +967 -0
  36. package/src/i18n/screen/pt.mjs +967 -0
  37. package/src/i18n/screen/zh.mjs +967 -0
  38. package/src/importers/apple-music-library/index.mjs +0 -16
  39. package/src/importers/apple-music-library/sqlite-projection.mjs +51 -9
  40. package/src/integrations/apple-music/catalog.mjs +166 -14
  41. package/src/integrations/apple-music/music-app.mjs +232 -0
  42. package/src/integrations/apple-music/storefront.mjs +28 -0
  43. package/src/integrations/apple-music/terminal-preview-player.mjs +221 -0
  44. package/src/integrations/lastfm/history.mjs +221 -0
  45. package/src/integrations/lastfm/settings.mjs +75 -0
  46. package/src/integrations/netease/ncm-cli-player.mjs +328 -0
  47. package/src/integrations/open-music-similarity/artist-radio.mjs +26 -18
  48. package/src/integrations/public-playlists.mjs +2 -1
  49. package/src/integrations/spotify/account-data-profile.mjs +14 -6
  50. package/src/integrations/spotify/authentication.mjs +149 -15
  51. package/src/integrations/spotify/catalog-resolver.mjs +9 -6
  52. package/src/integrations/spotify/connection.mjs +2 -1
  53. package/src/integrations/spotify/credential-store.mjs +4 -0
  54. package/src/integrations/spotify/extended-streaming-history.mjs +11 -11
  55. package/src/integrations/spotify/history-archive.mjs +1 -1
  56. package/src/integrations/spotify/library-snapshot.mjs +227 -0
  57. package/src/integrations/spotify/recent-activity.mjs +2 -0
  58. package/src/integrations/spotify/service.mjs +873 -69
  59. package/src/integrations/spotify/web-api-client.mjs +410 -127
  60. package/src/integrations/web/brave-web.mjs +45 -0
  61. package/src/integrations/web/codex-web.mjs +15 -82
  62. package/src/integrations/web/deepseek-web.mjs +81 -0
  63. package/src/integrations/web/web-research.mjs +119 -0
  64. package/src/integrations/web/web-result.mjs +215 -0
  65. package/src/integrations/youtube-music/takeout.mjs +3 -1
  66. package/src/memory/local-memory-store.mjs +542 -57
  67. package/src/profile/history-import.mjs +42 -6
  68. package/src/profile/listener-corrections.mjs +22 -0
  69. package/src/profile/listener-profile-build.mjs +461 -0
  70. package/src/profile/listener-profile-store.mjs +130 -0
  71. package/src/profile/listener-profile-verification.mjs +68 -0
  72. package/src/profile/listener-profile-worker.mjs +179 -0
  73. package/src/profile/listening-history-store.mjs +640 -17
  74. package/src/profile/listening-profile-projection.mjs +454 -86
  75. package/src/profile/local-music-data.mjs +1 -1
  76. package/src/profile/moondog-suggestions.mjs +184 -0
  77. package/src/profile/music-providers.mjs +11 -7
  78. package/src/profile/profile-exploration.mjs +92 -0
  79. package/src/profile/recorded-measures.mjs +24 -0
  80. package/src/profile/spotify-archive-taste.mjs +0 -4
  81. package/src/runtime/pi/agent-runtime.mjs +2536 -692
  82. package/src/runtime/pi/authentication.mjs +34 -1
  83. package/src/runtime/pi/configured-runtime.mjs +22 -6
  84. package/src/runtime/pi/conversation-name.mjs +53 -0
  85. package/src/runtime/pi/memory-agent-runtime.mjs +2 -2
  86. package/src/runtime/pi/model-catalog.mjs +28 -5
  87. package/src/runtime/pi/model-settings.mjs +202 -0
  88. package/src/runtime/pi/model-transport.mjs +10 -0
  89. package/src/runtime/pi/persistent-credential-store.mjs +67 -31
  90. package/src/runtime/pi/profile-build-runtime.mjs +161 -0
  91. package/src/runtime/pi/public-model-catalog.mjs +288 -0
  92. package/src/runtime/pi/runtime-settings.mjs +10 -2
  93. package/src/runtime/pi/skills/listener-profile/SKILL.md +48 -0
  94. package/src/runtime/pi/tool-trace.mjs +37 -0
  95. package/src/surfaces/cli/auth-command.mjs +12 -4
  96. package/src/surfaces/cli/brand-components.mjs +310 -132
  97. package/src/surfaces/cli/brand-theme.mjs +51 -28
  98. package/src/surfaces/cli/command-completions.mjs +58 -42
  99. package/src/surfaces/cli/format-output.mjs +199 -388
  100. package/src/surfaces/cli/history-import-view.mjs +292 -139
  101. package/src/surfaces/cli/import-guides.mjs +2 -0
  102. package/src/surfaces/cli/listener-profile-command.mjs +92 -0
  103. package/src/surfaces/cli/listening-menu.mjs +7 -4
  104. package/src/surfaces/cli/profile-command.mjs +30 -21
  105. package/src/surfaces/cli/seasons-chart.mjs +87 -0
  106. package/src/surfaces/cli/spotify-command.mjs +54 -6
  107. package/src/surfaces/cli/taste-profile-model.mjs +78 -79
  108. package/src/surfaces/cli/taste-profile-view.mjs +33 -26
  109. package/src/surfaces/cli/terminal-art.mjs +140 -35
  110. package/src/surfaces/cli/tui.mjs +1066 -357
  111. package/src/surfaces/cli/update-command.mjs +32 -0
  112. package/src/surfaces/cli/web-command.mjs +53 -14
  113. package/src/surfaces/html/tasteprint.mjs +43 -70
  114. package/contracts/v1/capability-policy.schema.json +0 -572
  115. package/contracts/v1/profile-evidence.schema.json +0 -237
  116. package/contracts/v1/tool-invocation.schema.json +0 -318
  117. package/contracts/v1/tool-receipt.schema.json +0 -1066
  118. package/scripts/demo-studio.mjs +0 -58
  119. package/src/core/apple-data-migration.mjs +0 -50
  120. package/src/demo/moondog-interactive-tasteprint-demo.mjs +0 -293
  121. package/src/demo/moondog-tasteprint-demo.mjs +0 -631
  122. package/src/integrations/spotify/index.mjs +0 -80
  123. package/src/surfaces/web/showcase.mjs +0 -272
  124. package/src/surfaces/web/studio-page.mjs +0 -4148
  125. package/src/surfaces/web/studio.mjs +0 -2288
@@ -1,631 +0,0 @@
1
- export const PUBLIC_TASTEPRINT_DEMO_GENERATED_AT =
2
- "2026-08-25T12:00:00.000Z";
3
-
4
- function distributeSyntheticTotal(total, weights) {
5
- const weightTotal = weights.reduce((sum, weight) => sum + weight, 0);
6
- let remaining = total;
7
- return weights.map((weight, index) => {
8
- if (index === weights.length - 1) return remaining;
9
- const value = Math.floor((total * weight) / weightTotal);
10
- remaining -= value;
11
- return value;
12
- });
13
- }
14
-
15
- function createSyntheticMonthlyActivity() {
16
- const periods = [
17
- {
18
- year: 2023,
19
- firstMonth: 9,
20
- events: 2_480,
21
- minutes: 8_940,
22
- weights: [1.1, 0.8, 1.25, 0.95],
23
- },
24
- {
25
- year: 2024,
26
- firstMonth: 1,
27
- events: 5_210,
28
- minutes: 17_820,
29
- weights: [1.2, 0.95, 1.05, 0.8, 0.9, 1.35, 1.18, 0.92, 1.12, 0.86, 0.98, 1.28],
30
- },
31
- {
32
- year: 2025,
33
- firstMonth: 1,
34
- events: 6_184,
35
- minutes: 21_636,
36
- weights: [1.32, 1.08, 0.92, 1.16, 0.88, 1.24, 1.02, 0.96, 1.34, 1.1, 0.9, 1.28],
37
- },
38
- {
39
- year: 2026,
40
- firstMonth: 1,
41
- events: 4_522,
42
- minutes: 13_788,
43
- weights: [1.15, 0.92, 1.28, 0.86, 1.04, 1.34, 0.98, 1.2],
44
- },
45
- ];
46
- const months = periods.flatMap((period) => {
47
- const eventCounts = distributeSyntheticTotal(period.events, period.weights);
48
- const minuteCounts = distributeSyntheticTotal(period.minutes, period.weights);
49
- return period.weights.map((_, index) => {
50
- const eventCount = eventCounts[index];
51
- return {
52
- month: `${period.year}-${String(period.firstMonth + index).padStart(2, "0")}`,
53
- event_count: eventCount,
54
- engaged_play_count: Math.round(eventCount * 0.845),
55
- listening_minutes: minuteCounts[index],
56
- distinct_tracks: Math.max(1, Math.round(eventCount * 0.36)),
57
- };
58
- });
59
- });
60
- return {
61
- timezone: "UTC",
62
- first_month: months[0].month,
63
- last_month: months.at(-1).month,
64
- retained_span_months: months.length,
65
- represented_month_count: months.length,
66
- active_month_count: months.length,
67
- omitted_earlier_month_count: 0,
68
- peak_listening_minutes: Math.max(
69
- ...months.map((month) => month.listening_minutes),
70
- ),
71
- months,
72
- };
73
- }
74
-
75
- function createSyntheticListeningSeasons() {
76
- const anchors = [
77
- ["Mara Vale", "Midnight Lines", "Night Transit"],
78
- ["Sable Arcade", "Signal Garden", "Night Survey"],
79
- ["North Window", "Glass Highway", "Pale Signals"],
80
- ["Lumen Choir", "Amber Receiver", "Open Frequencies"],
81
- ["Ash Meridian", "Blue Exit", "Afterimage"],
82
- ["Static Bloom", "Soft Static", "Quiet Machinery"],
83
- ["Mara Vale", "Night Transit", "Night Transit"],
84
- ["Juniper City", "Empty Overpass", "Exit Weather"],
85
- ["Elsewhere Signal", "Parallel Rooms", "Long Distance"],
86
- ["Cinder Lake", "Weather Memory", "Shoreline Code"],
87
- ["North Window", "First Light Behind Us", "Pale Signals"],
88
- ["Drift Assembly", "Northern Relay", "Moving Weather"],
89
- ["New Coast Archive", "Blue Hour Index", "Tide Tables"],
90
- ];
91
- const groups = new Map();
92
- for (const month of createSyntheticMonthlyActivity().months) {
93
- const year = Number(month.month.slice(0, 4));
94
- const monthNumber = Number(month.month.slice(5, 7));
95
- const quarter = Math.floor((monthNumber - 1) / 3) + 1;
96
- const key = `${year}-Q${quarter}`;
97
- const group = groups.get(key) ?? [];
98
- group.push(month);
99
- groups.set(key, group);
100
- }
101
- const seasons = [...groups.entries()].map(([key, months], index) => {
102
- const eventCount = months.reduce(
103
- (sum, month) => sum + month.event_count,
104
- 0,
105
- );
106
- const engagedPlayCount = months.reduce(
107
- (sum, month) => sum + month.engaged_play_count,
108
- 0,
109
- );
110
- const listeningMinutes = months.reduce(
111
- (sum, month) => sum + month.listening_minutes,
112
- 0,
113
- );
114
- const distinctTracks = Math.max(
115
- 1,
116
- Math.round(months.reduce((sum, month) => sum + month.distinct_tracks, 0) * 0.72),
117
- );
118
- const firstObservedShare = Math.max(0.18, 0.7 - index * 0.04);
119
- const firstObservedTracks = Math.round(
120
- distinctTracks * firstObservedShare,
121
- );
122
- const [artist, track, release] = anchors[index];
123
- const leadingEventCount = Math.max(1, Math.round(eventCount * 0.16));
124
- const leadingEngagedPlayCount = Math.round(leadingEventCount * 0.88);
125
- const signaturePlayCount = Math.max(1, Math.round(eventCount * 0.035));
126
- const signatureEngagedPlayCount = Math.round(signaturePlayCount * 0.91);
127
- return {
128
- key,
129
- start_month: months[0].month,
130
- end_month: months.at(-1).month,
131
- retained_month_count: months.length,
132
- active_month_count: months.length,
133
- event_count: eventCount,
134
- engaged_play_count: engagedPlayCount,
135
- listening_minutes: listeningMinutes,
136
- distinct_tracks: distinctTracks,
137
- first_observed_tracks: firstObservedTracks,
138
- returning_tracks: distinctTracks - firstObservedTracks,
139
- leading_artist: {
140
- name: artist,
141
- event_count: leadingEventCount,
142
- engaged_play_count: leadingEngagedPlayCount,
143
- listening_minutes: Math.max(1, Math.round(listeningMinutes * 0.17)),
144
- distinct_tracks: Math.max(1, Math.round(distinctTracks * 0.14)),
145
- },
146
- signature_track: {
147
- label: track,
148
- artist_credit: artist,
149
- release,
150
- play_count: signaturePlayCount,
151
- engaged_play_count: signatureEngagedPlayCount,
152
- listening_minutes: Math.max(1, Math.round(signaturePlayCount * 4.6)),
153
- explicit_skips: signaturePlayCount - signatureEngagedPlayCount,
154
- },
155
- };
156
- });
157
- return {
158
- timezone: "UTC",
159
- alignment: "calendar_quarter",
160
- season_length_months: 3,
161
- retained_first_season: seasons[0].key,
162
- represented_first_season: seasons[0].key,
163
- last_season: seasons.at(-1).key,
164
- retained_season_count: seasons.length,
165
- represented_season_count: seasons.length,
166
- active_season_count: seasons.length,
167
- represented_active_season_count: seasons.length,
168
- omitted_earlier_season_count: 0,
169
- omitted_earlier_active_season_count: 0,
170
- seasons,
171
- };
172
- }
173
-
174
- const publicTasteprintDemoProfile = {
175
- profile_version: "profile-projection/synthetic-demo-1",
176
- coverage: {
177
- effective_listening_events: 18_420,
178
- profiled_listening_events: 18_396,
179
- listening_hours: 1_036.4,
180
- listening_tracks: 3_260,
181
- resolved_listening_tracks: 3_218,
182
- spotify_saved_tracks: 286,
183
- spotify_saved_albums: 72,
184
- spotify_followed_artists: 34,
185
- spotify_playlist_memberships: 642,
186
- verified_search_interactions: 41,
187
- tracks_observed: 1_240,
188
- loved_or_favorited: 94,
189
- },
190
- listening_behavior: {
191
- enduring_artists: [
192
- { name: "Mara Vale", play_count: 1_230, listening_minutes: 5_420, distinct_tracks: 88 },
193
- { name: "North Window", play_count: 1_104, listening_minutes: 4_810, distinct_tracks: 73 },
194
- { name: "Ash Meridian", play_count: 846, listening_minutes: 3_650, distinct_tracks: 61 },
195
- { name: "Lumen Choir", play_count: 698, listening_minutes: 2_880, distinct_tracks: 49 },
196
- { name: "Static Bloom", play_count: 605, listening_minutes: 2_430, distinct_tracks: 44 },
197
- { name: "Juniper City", play_count: 531, listening_minutes: 2_150, distinct_tracks: 39 },
198
- { name: "Cinder Lake", play_count: 477, listening_minutes: 1_920, distinct_tracks: 36 },
199
- { name: "Elsewhere Signal", play_count: 418, listening_minutes: 1_760, distinct_tracks: 31 },
200
- { name: "Glass Atlas", play_count: 376, listening_minutes: 1_550, distinct_tracks: 28 },
201
- { name: "Sable Arcade", play_count: 319, listening_minutes: 1_320, distinct_tracks: 25 },
202
- ],
203
- recent_artists: [
204
- { name: "North Window", play_count: 98, listening_minutes: 620, distinct_tracks: 18 },
205
- { name: "Juniper City", play_count: 86, listening_minutes: 540, distinct_tracks: 14 },
206
- { name: "Drift Assembly", play_count: 77, listening_minutes: 468, distinct_tracks: 11 },
207
- { name: "Mara Vale", play_count: 69, listening_minutes: 430, distinct_tracks: 16 },
208
- { name: "New Coast Archive", play_count: 62, listening_minutes: 386, distinct_tracks: 9 },
209
- { name: "Lumen Choir", play_count: 55, listening_minutes: 344, distinct_tracks: 12 },
210
- { name: "Static Bloom", play_count: 51, listening_minutes: 308, distinct_tracks: 10 },
211
- { name: "Low Lanterns", play_count: 44, listening_minutes: 271, distinct_tracks: 8 },
212
- { name: "Ash Meridian", play_count: 38, listening_minutes: 236, distinct_tracks: 9 },
213
- { name: "Glass Atlas", play_count: 31, listening_minutes: 194, distinct_tracks: 7 },
214
- ],
215
- repeat_tracks: [
216
- { label: "Midnight Lines", artist_credit: "Mara Vale", release: "Night Transit", play_count: 64, listening_minutes: 312 },
217
- { label: "Glass Highway", artist_credit: "North Window", release: "Pale Signals", play_count: 57, listening_minutes: 286 },
218
- { label: "Blue Exit", artist_credit: "Ash Meridian", release: "Afterimage", play_count: 49, listening_minutes: 241 },
219
- { label: "Soft Static", artist_credit: "Static Bloom", release: "Quiet Machinery", play_count: 43, listening_minutes: 218 },
220
- { label: "First Light Behind Us", artist_credit: "North Window", release: "Pale Signals", play_count: 39, listening_minutes: 201 },
221
- { label: "Amber Receiver", artist_credit: "Lumen Choir", release: "Open Frequencies", play_count: 36, listening_minutes: 188 },
222
- { label: "Empty Overpass", artist_credit: "Juniper City", release: "Exit Weather", play_count: 34, listening_minutes: 173 },
223
- { label: "Weather Memory", artist_credit: "Cinder Lake", release: "Shoreline Code", play_count: 31, listening_minutes: 162 },
224
- { label: "Parallel Rooms", artist_credit: "Elsewhere Signal", release: "Long Distance", play_count: 29, listening_minutes: 151 },
225
- { label: "Signal Garden", artist_credit: "Glass Atlas", release: "Unfolding Maps", play_count: 27, listening_minutes: 143 },
226
- ],
227
- recent_tracks: [
228
- { label: "Northern Relay", artist_credit: "Drift Assembly", release: "Moving Weather", play_count: 18, listening_minutes: 96 },
229
- { label: "Exit Weather", artist_credit: "Juniper City", release: "Exit Weather", play_count: 16, listening_minutes: 88 },
230
- { label: "Blue Hour Index", artist_credit: "New Coast Archive", release: "Tide Tables", play_count: 15, listening_minutes: 82 },
231
- { label: "First Light Behind Us", artist_credit: "North Window", release: "Pale Signals", play_count: 14, listening_minutes: 76 },
232
- { label: "Low Voltage Moon", artist_credit: "Low Lanterns", release: "Street Astronomy", play_count: 13, listening_minutes: 71 },
233
- { label: "Midnight Lines", artist_credit: "Mara Vale", release: "Night Transit", play_count: 12, listening_minutes: 65 },
234
- { label: "Amber Receiver", artist_credit: "Lumen Choir", release: "Open Frequencies", play_count: 11, listening_minutes: 61 },
235
- { label: "Soft Static", artist_credit: "Static Bloom", release: "Quiet Machinery", play_count: 10, listening_minutes: 56 },
236
- { label: "Unfolding Maps", artist_credit: "Glass Atlas", release: "Unfolding Maps", play_count: 9, listening_minutes: 51 },
237
- { label: "Blue Exit", artist_credit: "Ash Meridian", release: "Afterimage", play_count: 8, listening_minutes: 45 },
238
- ],
239
- rediscovery_tracks: [
240
- {
241
- label: "Quiet Coordinates",
242
- artist_credit: "Sable Arcade",
243
- release: "Night Survey",
244
- play_count: 32,
245
- listening_minutes: 168,
246
- first_played_at: "2023-11-18T21:14:00.000Z",
247
- last_played_at: "2025-11-26T19:42:00.000Z",
248
- quiet_days: 271,
249
- peak_year: 2024,
250
- peak_year_play_count: 18,
251
- peak_year_listening_minutes: 96,
252
- rediscovery_signal: "saved-library state",
253
- },
254
- {
255
- label: "After the Floodlights",
256
- artist_credit: "Cinder Lake",
257
- release: "Shoreline Code",
258
- play_count: 27,
259
- listening_minutes: 142,
260
- first_played_at: "2024-02-09T18:30:00.000Z",
261
- last_played_at: "2025-12-19T23:11:00.000Z",
262
- quiet_days: 248,
263
- peak_year: 2025,
264
- peak_year_play_count: 15,
265
- peak_year_listening_minutes: 81,
266
- rediscovery_signal: "private playlist curation",
267
- },
268
- {
269
- label: "Signal Garden",
270
- artist_credit: "Glass Atlas",
271
- release: "Unfolding Maps",
272
- play_count: 27,
273
- listening_minutes: 143,
274
- first_played_at: "2023-10-21T20:08:00.000Z",
275
- last_played_at: "2026-01-08T14:20:00.000Z",
276
- quiet_days: 228,
277
- peak_year: 2024,
278
- peak_year_play_count: 13,
279
- peak_year_listening_minutes: 70,
280
- rediscovery_signal: "historical attention only",
281
- },
282
- ],
283
- historical_return_tracks: [
284
- {
285
- label: "Quiet Coordinates",
286
- artist_credit: "Sable Arcade",
287
- release: "Night Survey",
288
- play_count: 32,
289
- engaged_play_count: 31,
290
- listening_minutes: 168,
291
- explicit_skips: 1,
292
- first_played_at: "2023-11-18T21:14:00.000Z",
293
- last_played_at: "2025-11-26T19:42:00.000Z",
294
- return_count: 2,
295
- longest_gap_days: 421,
296
- latest_return_at: "2025-11-26T19:42:00.000Z",
297
- latest_return_gap_days: 316,
298
- historical_return_signal: "saved-library state",
299
- },
300
- {
301
- label: "Glass Highway",
302
- artist_credit: "North Window",
303
- release: "Pale Signals",
304
- play_count: 57,
305
- engaged_play_count: 54,
306
- listening_minutes: 286,
307
- explicit_skips: 3,
308
- first_played_at: "2024-01-19T20:10:00.000Z",
309
- last_played_at: "2026-03-09T22:12:00.000Z",
310
- return_count: 2,
311
- longest_gap_days: 318,
312
- latest_return_at: "2026-03-09T22:12:00.000Z",
313
- latest_return_gap_days: 318,
314
- historical_return_signal: "explicit listener preference",
315
- },
316
- {
317
- label: "Midnight Lines",
318
- artist_credit: "Mara Vale",
319
- release: "Night Transit",
320
- play_count: 64,
321
- engaged_play_count: 61,
322
- listening_minutes: 312,
323
- explicit_skips: 3,
324
- first_played_at: "2023-06-03T21:32:00.000Z",
325
- last_played_at: "2026-06-04T21:46:00.000Z",
326
- return_count: 1,
327
- longest_gap_days: 732,
328
- latest_return_at: "2026-06-04T21:46:00.000Z",
329
- latest_return_gap_days: 732,
330
- historical_return_signal: "saved-library state",
331
- },
332
- ],
333
- back_to_back_tracks: [
334
- {
335
- label: "Glass Highway",
336
- artist_credit: "North Window",
337
- release: "Pale Signals",
338
- play_count: 57,
339
- engaged_play_count: 54,
340
- explicit_skips: 3,
341
- burst_count: 4,
342
- maximum_consecutive_plays: 5,
343
- plays_in_bursts: 14,
344
- listening_minutes_in_bursts: 71,
345
- latest_burst_at: "2026-03-09T22:12:00.000Z",
346
- sequence_signal: "adjacent retained plays",
347
- },
348
- {
349
- label: "Midnight Lines",
350
- artist_credit: "Mara Vale",
351
- release: "Night Transit",
352
- play_count: 64,
353
- engaged_play_count: 61,
354
- explicit_skips: 3,
355
- burst_count: 3,
356
- maximum_consecutive_plays: 4,
357
- plays_in_bursts: 10,
358
- listening_minutes_in_bursts: 49,
359
- latest_burst_at: "2026-06-04T21:46:00.000Z",
360
- sequence_signal: "adjacent retained plays",
361
- },
362
- {
363
- label: "Blue Exit",
364
- artist_credit: "Ash Meridian",
365
- release: "Afterimage",
366
- play_count: 49,
367
- engaged_play_count: 47,
368
- explicit_skips: 2,
369
- burst_count: 2,
370
- maximum_consecutive_plays: 3,
371
- plays_in_bursts: 6,
372
- listening_minutes_in_bursts: 30,
373
- latest_burst_at: "2026-03-09T22:12:00.000Z",
374
- sequence_signal: "adjacent retained plays",
375
- },
376
- ],
377
- time_capsule_tracks: [
378
- {
379
- label: "Midnight Lines",
380
- artist_credit: "Mara Vale",
381
- release: "Night Transit",
382
- identity_status: "resolved",
383
- capsule_year: 2023,
384
- year_play_count: 22,
385
- year_engaged_play_count: 21,
386
- year_listening_minutes: 108,
387
- year_explicit_skips: 1,
388
- lifetime_play_count: 64,
389
- lifetime_listening_minutes: 312,
390
- representative_signal: "saved-library state",
391
- },
392
- {
393
- label: "Glass Highway",
394
- artist_credit: "North Window",
395
- release: "Pale Signals",
396
- identity_status: "resolved",
397
- capsule_year: 2024,
398
- year_play_count: 27,
399
- year_engaged_play_count: 25,
400
- year_listening_minutes: 135,
401
- year_explicit_skips: 2,
402
- lifetime_play_count: 57,
403
- lifetime_listening_minutes: 286,
404
- representative_signal: "explicit listener preference",
405
- },
406
- {
407
- label: "Blue Exit",
408
- artist_credit: "Ash Meridian",
409
- release: "Afterimage",
410
- identity_status: "resolved",
411
- capsule_year: 2025,
412
- year_play_count: 31,
413
- year_engaged_play_count: 29,
414
- year_listening_minutes: 154,
415
- year_explicit_skips: 2,
416
- lifetime_play_count: 49,
417
- lifetime_listening_minutes: 241,
418
- representative_signal: "private playlist curation",
419
- },
420
- {
421
- label: "Northern Relay",
422
- artist_credit: "Drift Assembly",
423
- release: "Moving Weather",
424
- identity_status: "resolved",
425
- capsule_year: 2026,
426
- year_play_count: 18,
427
- year_engaged_play_count: 18,
428
- year_listening_minutes: 96,
429
- year_explicit_skips: 0,
430
- lifetime_play_count: 18,
431
- lifetime_listening_minutes: 96,
432
- representative_signal: "historical attention only",
433
- },
434
- ],
435
- history_arc: [
436
- { year: 2023, event_count: 2_480, listening_minutes: 8_940, distinct_tracks: 1_120, first_observed_tracks: 1_120, top_artist: { name: "Mara Vale", play_count: 340, listening_minutes: 1_480 } },
437
- { year: 2024, event_count: 5_210, listening_minutes: 17_820, distinct_tracks: 1_680, first_observed_tracks: 982, top_artist: { name: "North Window", play_count: 480, listening_minutes: 2_160 } },
438
- { year: 2025, event_count: 6_184, listening_minutes: 21_636, distinct_tracks: 1_940, first_observed_tracks: 743, top_artist: { name: "Mara Vale", play_count: 590, listening_minutes: 2_740 } },
439
- { year: 2026, event_count: 4_522, listening_minutes: 13_788, distinct_tracks: 1_360, first_observed_tracks: 415, top_artist: { name: "North Window", play_count: 285, listening_minutes: 1_410 } },
440
- ],
441
- monthly_activity: createSyntheticMonthlyActivity(),
442
- listening_seasons: createSyntheticListeningSeasons(),
443
- artist_relationships: [
444
- { name: "Mara Vale", first_year: 2023, last_year: 2026, active_years: 4, span_years: 4, play_count: 1_230, listening_minutes: 5_420 },
445
- { name: "Ash Meridian", first_year: 2023, last_year: 2026, active_years: 4, span_years: 4, play_count: 846, listening_minutes: 3_650 },
446
- { name: "North Window", first_year: 2024, last_year: 2026, active_years: 3, span_years: 3, play_count: 1_104, listening_minutes: 4_810 },
447
- { name: "Lumen Choir", first_year: 2024, last_year: 2026, active_years: 3, span_years: 3, play_count: 698, listening_minutes: 2_880 },
448
- ],
449
- year_transitions: [
450
- { from_year: 2023, to_year: 2024, artist_limit: 10, from_artist_count: 10, to_artist_count: 10, retained_artist_count: 6, new_artist_count: 4, continuity_percent: 60, retained_artists: ["Mara Vale", "Ash Meridian", "Static Bloom"], new_artists: ["North Window", "Lumen Choir", "Glass Atlas"] },
451
- { from_year: 2024, to_year: 2025, artist_limit: 10, from_artist_count: 10, to_artist_count: 10, retained_artist_count: 7, new_artist_count: 3, continuity_percent: 70, retained_artists: ["Mara Vale", "North Window", "Lumen Choir"], new_artists: ["Ash Meridian", "Juniper City", "Elsewhere Signal"] },
452
- { from_year: 2025, to_year: 2026, artist_limit: 10, from_artist_count: 10, to_artist_count: 10, retained_artist_count: 5, new_artist_count: 5, continuity_percent: 50, retained_artists: ["North Window", "Mara Vale", "Ash Meridian"], new_artists: ["Drift Assembly", "New Coast Archive", "Low Lanterns"] },
453
- ],
454
- release_depth: [
455
- { title: "Night Transit", artist_credit: "Mara Vale", distinct_tracks: 11, play_count: 284, engaged_play_count: 267, listening_minutes: 1_246, first_year: 2023, last_year: 2026, active_years: 4 },
456
- { title: "Pale Signals", artist_credit: "North Window", distinct_tracks: 10, play_count: 251, engaged_play_count: 238, listening_minutes: 1_104, first_year: 2024, last_year: 2026, active_years: 3 },
457
- { title: "Afterimage", artist_credit: "Ash Meridian", distinct_tracks: 9, play_count: 198, engaged_play_count: 184, listening_minutes: 862, first_year: 2023, last_year: 2026, active_years: 4 },
458
- { title: "Open Frequencies", artist_credit: "Lumen Choir", distinct_tracks: 8, play_count: 171, engaged_play_count: 160, listening_minutes: 734, first_year: 2024, last_year: 2026, active_years: 3 },
459
- { title: "Quiet Machinery", artist_credit: "Static Bloom", distinct_tracks: 7, play_count: 146, engaged_play_count: 133, listening_minutes: 618, first_year: 2023, last_year: 2026, active_years: 4 },
460
- ],
461
- session_summary: {
462
- source: "spotify_extended_history",
463
- method: "track_stop_gap",
464
- gap_minutes: 30,
465
- event_count: 17_980,
466
- session_count: 2_500,
467
- median_plays: 5,
468
- median_listening_minutes: 17,
469
- single_play_sessions: 600,
470
- short_sequence_sessions: 850,
471
- extended_sequence_sessions: 1_050,
472
- extended_sequence_minimum_plays: 5,
473
- extended_sequence_percent: 42,
474
- },
475
- context: {
476
- recent_window_days: 90,
477
- effective_events_profiled: 18_396,
478
- start_reason_events: 17_980,
479
- trackdone_starts: 11_920,
480
- end_reason_events: 17_980,
481
- skip_state_events: 17_980,
482
- explicit_skips: 2_860,
483
- trackdone_endings: 12_104,
484
- direct_selection_starts: 4_320,
485
- shuffle_state_events: 17_980,
486
- shuffle_events: 5_940,
487
- offline_state_events: 17_980,
488
- offline_events: 214,
489
- incognito_events_excluded: 24,
490
- rediscovery_quiet_days: 90,
491
- rediscovery_minimum_plays: 3,
492
- rediscovery_minimum_engaged_plays: 2,
493
- rediscovery_minimum_listening_minutes: 10,
494
- historical_return_minimum_gap_days: 180,
495
- historical_return_minimum_plays: 3,
496
- historical_return_minimum_engaged_plays: 3,
497
- historical_return_minimum_listening_minutes: 10,
498
- back_to_back_minimum_consecutive_plays: 2,
499
- back_to_back_minimum_played_seconds: 30,
500
- back_to_back_maximum_gap_minutes: 30,
501
- monthly_activity_maximum_months: 240,
502
- listening_season_maximum_seasons: 80,
503
- time_capsule_minimum_years: 2,
504
- time_capsule_minimum_engaged_plays: 2,
505
- time_capsule_minimum_listening_minutes: 5,
506
- relationship_minimum_years: 2,
507
- continuity_artist_limit: 10,
508
- release_minimum_distinct_tracks: 3,
509
- session_gap_minutes: 30,
510
- extended_sequence_minimum_plays: 5,
511
- },
512
- },
513
- strong_preferences: [
514
- { label: "Midnight Lines", signal: "Loved and saved" },
515
- { label: "Glass Highway", signal: "Favorited" },
516
- { label: "Mara Vale", signal: "Followed artist" },
517
- { label: "Night Transit", signal: "Saved album" },
518
- { label: "First Light Behind Us", signal: "Playlist anchor" },
519
- { label: "North Window", signal: "Followed artist" },
520
- ],
521
- artist_facets: [
522
- { name: "Mara Vale" },
523
- { name: "North Window" },
524
- { name: "Ash Meridian" },
525
- { name: "Lumen Choir" },
526
- { name: "Static Bloom" },
527
- { name: "Juniper City" },
528
- ],
529
- genre_facets: [
530
- { name: "Art Pop" },
531
- { name: "Ambient Rock" },
532
- { name: "Electronic" },
533
- { name: "Dream Pop" },
534
- { name: "Post-Rock" },
535
- { name: "Alternative" },
536
- ],
537
- curated_preferences: {
538
- saved_tracks: [
539
- { label: "Midnight Lines", artist_credit: "Mara Vale", release: "Night Transit", listening_minutes: 312 },
540
- { label: "Glass Highway", artist_credit: "North Window", release: "Pale Signals", listening_minutes: 286 },
541
- { label: "Blue Exit", artist_credit: "Ash Meridian", release: "Afterimage", listening_minutes: 241 },
542
- { label: "Amber Receiver", artist_credit: "Lumen Choir", release: "Open Frequencies", listening_minutes: 188 },
543
- { label: "Signal Garden", artist_credit: "Glass Atlas", release: "Unfolding Maps", listening_minutes: 143 },
544
- ],
545
- playlist_anchors: [
546
- { label: "First Light Behind Us", artist_credit: "North Window", release: "Pale Signals", playlist_count: 5 },
547
- { label: "Midnight Lines", artist_credit: "Mara Vale", release: "Night Transit", playlist_count: 4 },
548
- { label: "Soft Static", artist_credit: "Static Bloom", release: "Quiet Machinery", playlist_count: 4 },
549
- { label: "Parallel Rooms", artist_credit: "Elsewhere Signal", release: "Long Distance", playlist_count: 3 },
550
- { label: "Weather Memory", artist_credit: "Cinder Lake", release: "Shoreline Code", playlist_count: 3 },
551
- ],
552
- followed_artists: [
553
- { name: "Mara Vale", listening_minutes: 5_420 },
554
- { name: "North Window", listening_minutes: 4_810 },
555
- { name: "Ash Meridian", listening_minutes: 3_650 },
556
- { name: "Lumen Choir", listening_minutes: 2_880 },
557
- { name: "Juniper City", listening_minutes: 2_150 },
558
- ],
559
- saved_albums: [
560
- { label: "Night Transit", artist_credit: "Mara Vale" },
561
- { label: "Pale Signals", artist_credit: "North Window" },
562
- { label: "Afterimage", artist_credit: "Ash Meridian" },
563
- { label: "Open Frequencies", artist_credit: "Lumen Choir" },
564
- { label: "Quiet Machinery", artist_credit: "Static Bloom" },
565
- ],
566
- },
567
- search_intent: [
568
- { query: "Mara Vale", interactions: 5, result_entity_types: ["artist", "track"] },
569
- { query: "late night ambient rock", interactions: 4, result_entity_types: ["track", "playlist"] },
570
- { query: "North Window", interactions: 3, result_entity_types: ["artist", "album"] },
571
- { query: "post-rock instrumental", interactions: 3, result_entity_types: ["track"] },
572
- { query: "Quiet Machinery", interactions: 2, result_entity_types: ["album"] },
573
- ],
574
- provider_signals: {
575
- artists: [
576
- { name: "Mara Vale", best_rank: 1, periods: ["Demo 2025"] },
577
- { name: "North Window", best_rank: 2, periods: ["Demo 2025"] },
578
- { name: "Ash Meridian", best_rank: 3, periods: ["Demo 2025"] },
579
- { name: "Lumen Choir", best_rank: 4, periods: ["Demo 2025"] },
580
- { name: "Static Bloom", best_rank: 5, periods: ["Demo 2025"] },
581
- ],
582
- tracks: [
583
- { label: "Midnight Lines", artist_credit: "Mara Vale", best_rank: 1, periods: ["Demo 2025"] },
584
- { label: "Glass Highway", artist_credit: "North Window", best_rank: 2, periods: ["Demo 2025"] },
585
- { label: "Blue Exit", artist_credit: "Ash Meridian", best_rank: 3, periods: ["Demo 2025"] },
586
- { label: "Soft Static", artist_credit: "Static Bloom", best_rank: 4, periods: ["Demo 2025"] },
587
- { label: "Amber Receiver", artist_credit: "Lumen Choir", best_rank: 5, periods: ["Demo 2025"] },
588
- ],
589
- genres: [
590
- { name: "Art Pop", rank: 1, period: "Demo 2025" },
591
- { name: "Ambient Rock", rank: 2, period: "Demo 2025" },
592
- { name: "Electronic", rank: 3, period: "Demo 2025" },
593
- ],
594
- highlights: [
595
- { kind: "top_track", label: "Midnight Lines", related_label: "Mara Vale" },
596
- { kind: "discovery_month", label: "March", related_label: "Drift Assembly" },
597
- { kind: "return_track", label: "Glass Highway", related_label: "North Window" },
598
- ],
599
- metrics: [
600
- { name: "listening time", value: 62_184, unit: "minutes", period: "Demo lifetime" },
601
- { name: "effective events", value: 18_420, unit: "events", period: "Demo lifetime" },
602
- { name: "distinct tracks", value: 3_260, unit: "tracks", period: "Demo lifetime" },
603
- ],
604
- },
605
- listening_source: {
606
- listening_range: {
607
- earliest: "2023-09-01T08:00:00.000Z",
608
- latest: "2026-08-24T22:30:00.000Z",
609
- },
610
- },
611
- limitations: [
612
- "This page uses fictional demonstration data and does not describe a real listener.",
613
- "Listening duration and repetition support familiarity and attention, not liking by themselves.",
614
- "Explicit skip flags are contextual navigation evidence, not permanent dislikes.",
615
- "Recent and lifetime rankings use different time windows.",
616
- "Calendar-year listening arcs use UTC boundaries.",
617
- "A track's first appearance in retained history does not prove that it was newly discovered then.",
618
- "Rediscovery candidates are listen-again prompts, not preference claims.",
619
- "Historical returns are long-gap recurrence patterns, not proof of liking, nostalgia, or intentional absence.",
620
- "Played-back-to-back sequences describe adjacent retained plays, not repeat mode, intention, liking, or preference.",
621
- "Listening Time Machine tracks are deterministic calendar-year landmarks, not claims that they defined a year or remain preferred now.",
622
- "Release depth describes multi-track listening, not full-album playback, completion, ownership, or liking.",
623
- "Approximate sessions use a 30-minute gap between UTC track-stop timestamps and do not establish activity, mood, location, or intent.",
624
- "Provider-derived rankings remain quoted context rather than user assertions.",
625
- "Bar lengths are relative only within each displayed list.",
626
- ],
627
- };
628
-
629
- export function createPublicTasteprintDemoProfile() {
630
- return structuredClone(publicTasteprintDemoProfile);
631
- }