Skip to content

Commit

Permalink
Add more fields to artist page and improve State
Browse files Browse the repository at this point in the history
  • Loading branch information
fsktom committed Oct 11, 2024
1 parent e8e3ec0 commit 7b4e423
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 35 deletions.
5 changes: 4 additions & 1 deletion endsong_ui/src/summarize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ pub fn artist(entries: &SongEntries, artist: &Artist) {
let albums = get_sorted_playcount_list(album_map, top);

let plays = gather::plays(entries, artist);
let percentage_of_plays = format!("{:.2}", (plays as f64 / entries.len() as f64) * 100.0);
let percentage_of_plays = format!(
"{:.2}",
(plays as f64 / gather::all_plays(entries) as f64) * 100.0
);

let time_played = gather::listening_time(entries, artist);

Expand Down
42 changes: 39 additions & 3 deletions endsong_web/src/artist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@ struct ArtistTemplate<'a> {
artist: &'a Artist,
/// This artist's playcount
plays: usize,
/// Percentage of this artist's plays to the total playcount
percentage_of_plays: String,
/// Time spent listening to this artist
time_played: TimeDelta,
/// Date of first artist entry
first_listen: DateTime<Local>,
/// Date of most recent artist entry
last_listen: DateTime<Local>,
/// This artist's ranking compared to other artists (playcount)
position: usize,
}
/// GET `/artist/:artist_name(?id=usize)`
///
Expand All @@ -52,6 +60,11 @@ struct ArtistTemplate<'a> {
/// multiple artists with this name
/// but different capitalization,
/// and [`not_found`] if it's not in the dataset
#[expect(clippy::cast_precision_loss, reason = "necessary for % calc")]
#[expect(
clippy::missing_panics_doc,
reason = "unwraps which should never panic"
)]
pub async fn base(
State(state): State<Arc<AppState>>,
Path(artist_name): Path<String>,
Expand All @@ -63,7 +76,7 @@ pub async fn base(
"GET /artist/:artist_name(?query)"
);

let entries = state.entries.read().await;
let entries = &state.entries;

let Some(artists) = entries.find().artist(&artist_name) else {
return not_found().await.into_response();
Expand All @@ -82,9 +95,32 @@ pub async fn base(
return ArtistSelectionTemplate { artists }.into_response();
};

let (plays, position) = *state.artists.get(artist).unwrap();
let percentage_of_plays = format!(
"{:.2}",
(plays as f64 / gather::all_plays(entries) as f64) * 100.0
);

// unwrap ok bc already made sure artist exists earlier
let first_listen = entries
.iter()
.find(|entry| artist.is_entry(entry))
.unwrap()
.timestamp;
let last_listen = entries
.iter()
.rev()
.find(|entry| artist.is_entry(entry))
.unwrap()
.timestamp;

ArtistTemplate {
plays: gather::plays(&entries, artist),
time_played: gather::listening_time(&entries, artist),
plays,
position,
percentage_of_plays,
time_played: gather::listening_time(entries, artist),
first_listen,
last_listen,
artist,
}
.into_response()
Expand Down
2 changes: 1 addition & 1 deletion endsong_web/src/artists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub async fn elements(
) -> impl IntoResponse {
debug!(search = form.search, "POST /artists");

let artists = state.artists.read().await;
let artists = &state.artist_names;

let lowercase_search = form.search.to_lowercase();

Expand Down
30 changes: 21 additions & 9 deletions endsong_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,41 @@ pub mod artist;
pub mod artists;
pub mod r#static;

use std::collections::HashMap;
use std::sync::Arc;

use axum::{extract::State, http::StatusCode, response::IntoResponse};
use endsong::prelude::*;
use itertools::Itertools;
use rinja::Template;
use tokio::sync::RwLock;
use tracing::debug;

/// State shared across all handlers
#[derive(Clone)]
pub struct AppState {
/// Reference to the [`SongEntries`] instance used
pub entries: Arc<RwLock<SongEntries>>,
/// Sorted list of all artist names in the dataset
pub artists: Arc<RwLock<Vec<Arc<str>>>>,
pub entries: Arc<SongEntries>,
/// Sorted (ascending alphabetically) list of all artist names in the dataset
pub artist_names: Arc<Vec<Arc<str>>>,
/// Map of artists with their playcount (.0) and their position/ranking descending (.1)
pub artists: Arc<HashMap<Artist, (usize, usize)>>,
}
impl AppState {
/// Creates a new [`AppState`] within an [`Arc`]
#[must_use]
pub fn new(entries: SongEntries) -> Arc<Self> {
let artists: HashMap<Artist, (usize, usize)> = gather::artists(&entries)
.into_iter()
.sorted_unstable_by_key(|(art, plays)| (std::cmp::Reverse(*plays), art.clone()))
.enumerate()
// bc enumeration starts with 0 :P
.map(|(position, (art, plays))| (art, (plays, position + 1)))
.collect();

Arc::new(Self {
artists: Arc::new(RwLock::new(entries.artists())),
entries: Arc::new(RwLock::new(entries)),
artists: Arc::new(artists),
artist_names: Arc::new(entries.artists()),
entries: Arc::new(entries),
})
}
}
Expand Down Expand Up @@ -73,10 +85,10 @@ struct IndexTemplate {
pub async fn index(State(state): State<Arc<AppState>>) -> impl IntoResponse {
debug!("GET /");

let entries = state.entries.read().await;
let entries = &state.entries;

IndexTemplate {
total_listened: gather::total_listening_time(&entries),
playcount: gather::all_plays(&entries),
total_listened: gather::total_listening_time(entries),
playcount: gather::all_plays(entries),
}
}
46 changes: 29 additions & 17 deletions endsong_web/static/tailwind_style.css
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,10 @@ video {
display: none;
}

.ml-4 {
margin-left: 1rem;
}

.block {
display: block;
}
Expand All @@ -562,6 +566,10 @@ video {
display: flex;
}

.list-item {
display: list-item;
}

.w-full {
width: 100%;
}
Expand All @@ -570,6 +578,10 @@ video {
list-style-type: none;
}

.list-disc {
list-style-type: disc;
}

.flex-col {
flex-direction: column;
}
Expand Down Expand Up @@ -693,6 +705,10 @@ video {
font-weight: 700;
}

.font-semibold {
font-weight: 600;
}

.text-gray-900 {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
Expand All @@ -715,39 +731,35 @@ https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/
}

@media (prefers-color-scheme: dark) {
.dark\:border-gray-700 {
--tw-border-opacity: 1;
border-color: rgb(55 65 81 / var(--tw-border-opacity));
}

.dark\:border-gray-800 {
--tw-border-opacity: 1;
border-color: rgb(31 41 55 / var(--tw-border-opacity));
}

.dark\:bg-slate-800 {
.dark\:bg-gray-950 {
--tw-bg-opacity: 1;
background-color: rgb(30 41 59 / var(--tw-bg-opacity));
background-color: rgb(3 7 18 / var(--tw-bg-opacity));
}

.dark\:bg-slate-700 {
--tw-bg-opacity: 1;
background-color: rgb(51 65 85 / var(--tw-bg-opacity));
}

.dark\:bg-gray-950 {
.dark\:bg-slate-800 {
--tw-bg-opacity: 1;
background-color: rgb(3 7 18 / var(--tw-bg-opacity));
background-color: rgb(30 41 59 / var(--tw-bg-opacity));
}

.dark\:text-gray-100 {
--tw-text-opacity: 1;
color: rgb(243 244 246 / var(--tw-text-opacity));
}

.dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}

.dark\:text-gray-100 {
--tw-text-opacity: 1;
color: rgb(243 244 246 / var(--tw-text-opacity));
.dark\:shadow-none {
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.dark\:shadow-white {
Expand Down
39 changes: 35 additions & 4 deletions endsong_web/templates/artist.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,49 @@
{% block title %} {{ artist.name }} {% endblock %}
<!-- -->
{% block content %}
<h2 class="text-2xl">{{ artist.name }}</h2>
<h2 class="text-2xl font-bold">{{ artist.name }}</h2>
<section class="flex">
<article
class="flex w-full flex-col gap-3 rounded-lg border border-gray-200 p-7 shadow dark:shadow-white"
class="flex w-full flex-col gap-3 rounded-lg border border-gray-200 p-7 shadow dark:shadow-none"
>
<h2 class="self-center text-xl font-bold">General info</h2>
<h2 class="self-center text-xl font-semibold">General info</h2>
<ul class="list-none">
<li>Playcount: {{ plays }}</li>
<li>
Time spent listening:
<time datetime="{{ time_played }}">{{ time_played }}</time>
<ul class="ml-4 list-disc">
{% let minutes = time_played.num_minutes() %} {% let hours =
time_played.num_hours() %} {% let days = time_played.num_days() %}
<li>
<time datetime="{{ time_played }}"
>{{ minutes }} minute{{ minutes|pluralize }}</time
>
</li>
{% if hours != 0 %}
<li>
<time datetime="{{ time_played }}"
>or {{ hours }} hour{{ hours|pluralize }}</time
>
</li>
{% endif %} {% if days != 0 %}
<li>
<time datetime="{{ time_played }}"
>or {{ days }} day{{ days|pluralize }}</time
>
</li>
{% endif %}
</ul>
</li>
<li>
First listen:
<time datetime="{{ first_listen }}">{{ first_listen }}</time>
</li>
<li>
Last listen:
<time datetime="{{ last_listen }}">{{ last_listen }}</time>
</li>
<li>% of total plays: {{ percentage_of_plays }}%</li>
<li>#{{ position }} artist of all time</li>
</ul>
</article>
</section>
Expand Down
1 change: 1 addition & 0 deletions endsong_web/templates/artists.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
hx-post="/artists"
hx-trigger="input changed, search, load"
hx-target="#search-results"
autofocus
/>
</search>
<ul id="search-results" class="flex flex-col items-center text-lg"></ul>
Expand Down

0 comments on commit 7b4e423

Please sign in to comment.