+49
-3
src/components/LookUp.vue
+49
-3
src/components/LookUp.vue
···
32
const loading = ref(false);
33
const artists = ref<{ name: string; plays: number }[]>([]);
34
const tracks = ref<{ name: string; artist: string; plays: number }[]>([]);
35
const totalSongs = ref(0);
36
37
const formatNumber = (n: number) => n.toLocaleString();
38
39
const lookup = async () => {
40
loading.value = true;
···
59
let totalCount = 0;
60
let inner_tracks: { name: string; artist: string; plays: number }[] = [];
61
let inner_artists: { name: string; plays: number }[] = [];
62
63
let response = await agent.com.atproto.repo.listRecords({
64
repo: did,
···
82
) {
83
continue;
84
}
85
-
// new version of lexicon
86
if (play.value?.artists) {
87
for (const artist of play.value?.artists) {
88
let alreadyPlayed = inner_artists.find(
···
94
plays: 1,
95
});
96
} else {
97
-
console.log(`Artist already played: ${alreadyPlayed}`);
98
alreadyPlayed.plays++;
99
}
100
}
···
112
}
113
}
114
115
let alreadyPlayed = inner_tracks.find(
116
(a) => a.name === play.value.trackName,
117
);
···
126
} else if (alreadyPlayed) {
127
alreadyPlayed.plays++;
128
}
129
}
130
131
-
// update reactive values incrementally (top 10)
132
artists.value = inner_artists
133
.sort((a, b) => b.plays - a.plays)
134
.slice(0, 25);
···
137
.slice(0, 25);
138
totalSongs.value = totalCount;
139
140
cursor = response.data.cursor;
141
if (!cursor) break;
142
···
221
<td>{{ idx + 1 }}.</td>
222
<td>{{ formatNumber(artist.plays) }}</td>
223
<td>{{ artist.name }}</td>
224
</tr>
225
</tbody>
226
</table>
···
32
const loading = ref(false);
33
const artists = ref<{ name: string; plays: number }[]>([]);
34
const tracks = ref<{ name: string; artist: string; plays: number }[]>([]);
35
+
const topDays = ref<{ date: string; plays: number }[]>([]);
36
const totalSongs = ref(0);
37
38
const formatNumber = (n: number) => n.toLocaleString();
39
+
40
+
// Returns YYYY-MM-DD in the browser's local time zone
41
+
const localDayKey = (iso?: string): string | null => {
42
+
if (!iso) return null;
43
+
const d = new Date(iso);
44
+
if (isNaN(d.getTime())) return null;
45
+
const y = d.getFullYear();
46
+
const m = (d.getMonth() + 1).toString().padStart(2, "0");
47
+
const day = d.getDate().toString().padStart(2, "0");
48
+
return `${y}-${m}-${day}`;
49
+
};
50
51
const lookup = async () => {
52
loading.value = true;
···
71
let totalCount = 0;
72
let inner_tracks: { name: string; artist: string; plays: number }[] = [];
73
let inner_artists: { name: string; plays: number }[] = [];
74
+
const dayCountMap = new Map<string, number>();
75
76
let response = await agent.com.atproto.repo.listRecords({
77
repo: did,
···
95
) {
96
continue;
97
}
98
+
// Aggregate by artist(s)
99
if (play.value?.artists) {
100
for (const artist of play.value?.artists) {
101
let alreadyPlayed = inner_artists.find(
···
107
plays: 1,
108
});
109
} else {
110
alreadyPlayed.plays++;
111
}
112
}
···
124
}
125
}
126
127
+
// Aggregate by track
128
let alreadyPlayed = inner_tracks.find(
129
(a) => a.name === play.value.trackName,
130
);
···
139
} else if (alreadyPlayed) {
140
alreadyPlayed.plays++;
141
}
142
+
143
+
// Aggregate by local day using playedTime
144
+
const key = localDayKey(play.value?.playedTime);
145
+
if (key) {
146
+
dayCountMap.set(key, (dayCountMap.get(key) ?? 0) + 1);
147
+
}
148
}
149
150
+
// update reactive values incrementally (top 25)
151
artists.value = inner_artists
152
.sort((a, b) => b.plays - a.plays)
153
.slice(0, 25);
···
156
.slice(0, 25);
157
totalSongs.value = totalCount;
158
159
+
// compute top 25 days
160
+
topDays.value = Array.from(dayCountMap.entries())
161
+
.map(([date, plays]) => ({ date, plays }))
162
+
.sort((a, b) => b.plays - a.plays)
163
+
.slice(0, 25);
164
+
165
cursor = response.data.cursor;
166
if (!cursor) break;
167
···
246
<td>{{ idx + 1 }}.</td>
247
<td>{{ formatNumber(artist.plays) }}</td>
248
<td>{{ artist.name }}</td>
249
+
</tr>
250
+
</tbody>
251
+
</table>
252
+
</div>
253
+
</div>
254
+
<div v-if="topDays.length > 0" class="mt-8">
255
+
<h2 class="text-2xl font-bold mb-4">Top Days (Most Songs Played)</h2>
256
+
<div class="overflow-x-auto">
257
+
<table class="table w-full">
258
+
<thead>
259
+
<tr>
260
+
<th>Rank</th>
261
+
<th>Plays</th>
262
+
<th>Date (yyyy-mm-dd)</th>
263
+
</tr>
264
+
</thead>
265
+
<tbody>
266
+
<tr v-for="(day, idx) in topDays" :key="day.date">
267
+
<td>{{ idx + 1 }}.</td>
268
+
<td>{{ formatNumber(day.plays) }}</td>
269
+
<td>{{ day.date }}</td>
270
</tr>
271
</tbody>
272
</table>