Fixed liked track sorting
Build and Publish / Build and Publish Docker Image (push) Successful in 10m14s

This commit is contained in:
Ultradesu
2026-07-27 17:09:59 +01:00
parent 291265be7d
commit b0d8929b4c
6 changed files with 86 additions and 11 deletions
+9 -2
View File
@@ -1712,7 +1712,7 @@ async fn local_seed_needs_metadata_backfill(pool: &sqlx::PgPool, user_id: i64) -
async fn seed_local_user_state(pool: &sqlx::PgPool, user_id: i64) -> Result<()> {
let now = now_ms();
let like_rows = sqlx::query(
"SELECT ult.track_id, c.content_id
"SELECT ult.track_id, ult.created_at, c.content_id
FROM furumusic__user_liked_track ult
JOIN furumusic__track t ON t.id = ult.track_id
JOIN furumusic__media_file m ON m.id = t.audio_file_id
@@ -1729,6 +1729,7 @@ async fn seed_local_user_state(pool: &sqlx::PgPool, user_id: i64) -> Result<()>
continue;
};
let track_id: i64 = row.get("track_id");
let liked_hlc_ms = timestamp_from_iso(&row.get::<String, _>("created_at")).unwrap_or(now);
let fed_json = synced_fed_track_for_track(pool, track_id, &content_id)
.await?
.map(serde_json::to_value)
@@ -1743,7 +1744,7 @@ async fn seed_local_user_state(pool: &sqlx::PgPool, user_id: i64) -> Result<()>
)
.bind(user_id)
.bind(&content_id)
.bind(now)
.bind(liked_hlc_ms)
.bind(format!("local_seed:like:{track_id}"))
.bind(track_id)
.bind(fed_json)
@@ -4536,6 +4537,12 @@ fn iso_from_ms(ms: i64) -> String {
.to_string()
}
fn timestamp_from_iso(value: &str) -> Option<i64> {
chrono::DateTime::parse_from_rfc3339(value)
.ok()
.map(|value| value.timestamp_millis())
}
fn now_label() -> String {
let secs = (now_ms() / 1000).max(0);
format!(
+2
View File
@@ -78,6 +78,8 @@ pub(super) struct TrackItem {
#[derive(Debug, Serialize, JsonSchema)]
pub(super) struct PlaylistTrackItem {
pub(super) playlist_track_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) sort_key: Option<i64>,
#[serde(flatten)]
pub(super) track: TrackItem,
}
+40 -3
View File
@@ -4111,6 +4111,7 @@ async fn build_playlist_track_items(
.zip(playlist_track_ids)
.map(|(track, playlist_track_id)| PlaylistTrackItem {
playlist_track_id,
sort_key: None,
track,
})
.collect())
@@ -4309,14 +4310,50 @@ async fn likes_playlist_handler(
.await
.map_err(|e| cot::Error::internal(e.to_string()))?;
let track_items = build_track_items(tracks, pool)
let order_rows = sqlx::query(
"SELECT ult.track_id,
COALESCE(
fsl.hlc_ms,
(EXTRACT(EPOCH FROM ult.created_at::timestamptz) * 1000)::bigint,
0
) AS sort_key
FROM furumusic__user_liked_track ult
JOIN furumusic__track t ON t.id = ult.track_id
LEFT JOIN furumusic__media_file m ON m.id = t.audio_file_id
LEFT JOIN furumusic__federation_content_id_cache c
ON c.media_file_id = m.id AND c.sha256_hash = m.sha256_hash
LEFT JOIN furumusic__fed_state_like fsl
ON fsl.user_id = ult.user_id
AND fsl.content_id = c.content_id
AND fsl.liked = true
WHERE ult.user_id = $1",
)
.bind(user_id)
.fetch_all(pool)
.await
.map_err(|e| cot::Error::internal(e.to_string()))?;
let order_by_track = order_rows
.into_iter()
.map(|row| (row.get::<i64, _>("track_id"), row.get::<i64, _>("sort_key")))
.collect::<HashMap<_, _>>();
let mut track_items = build_track_items(tracks, pool)
.await?
.into_iter()
.map(|track| PlaylistTrackItem {
playlist_track_id: None,
sort_key: order_by_track.get(&track.id).copied(),
track,
})
.collect();
.collect::<Vec<_>>();
track_items.sort_by(|left, right| {
right
.sort_key
.cmp(&left.sort_key)
.then_with(|| left.track.content_id.cmp(&right.track.content_id))
.then_with(|| left.track.title.cmp(&right.track.title))
.then_with(|| left.track.id.cmp(&right.track.id))
});
Json(PlaylistDetail {
id: -1,
@@ -6293,7 +6330,7 @@ async fn federation_playlist_tracks_handler(
};
let rows = if path.id == -1 {
sqlx::query(
"SELECT content_id, 0::bigint AS position, fed_json
"SELECT content_id, hlc_ms AS position, fed_json
FROM furumusic__fed_state_like
WHERE user_id = $1 AND liked = true
AND local_track_id IS NULL AND fed_json IS NOT NULL