172 lines
6.2 KiB
Rust
172 lines
6.2 KiB
Rust
use super::*;
|
|
use crate::mapper::*;
|
|
|
|
impl SpacetimeClient {
|
|
pub async fn list_public_work_gallery_entries(
|
|
&self,
|
|
) -> Result<Vec<PublicWorkGalleryEntryRecord>, SpacetimeClientError> {
|
|
self.read_after_connect("list_public_work_gallery_entries", move |connection| {
|
|
let recent_play_counts = public_work_recent_play_counts_by_source(connection);
|
|
let mut entries = connection
|
|
.db()
|
|
.public_work_gallery_entry()
|
|
.iter()
|
|
.collect::<Vec<_>>();
|
|
sort_public_work_gallery_entries(&mut entries);
|
|
|
|
Ok(entries
|
|
.into_iter()
|
|
.map(|entry| {
|
|
let recent_play_count_7d = recent_play_counts
|
|
.get(&(entry.source_type.clone(), entry.profile_id.clone()))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
map_public_work_gallery_entry(entry, recent_play_count_7d)
|
|
})
|
|
.collect())
|
|
})
|
|
.await
|
|
}
|
|
|
|
pub async fn list_public_work_detail_entries(
|
|
&self,
|
|
) -> Result<Vec<PublicWorkDetailEntryRecord>, SpacetimeClientError> {
|
|
self.read_after_connect("list_public_work_detail_entries", move |connection| {
|
|
let recent_play_counts = public_work_recent_play_counts_by_source(connection);
|
|
let mut entries = connection
|
|
.db()
|
|
.public_work_detail_entry()
|
|
.iter()
|
|
.collect::<Vec<_>>();
|
|
sort_public_work_detail_entries(&mut entries);
|
|
|
|
Ok(entries
|
|
.into_iter()
|
|
.map(|entry| {
|
|
let recent_play_count_7d = recent_play_counts
|
|
.get(&(entry.source_type.clone(), entry.profile_id.clone()))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
map_public_work_gallery_entry_to_detail_entry(entry, recent_play_count_7d)
|
|
})
|
|
.collect())
|
|
})
|
|
.await
|
|
}
|
|
|
|
pub async fn get_public_work_detail_by_code(
|
|
&self,
|
|
public_work_code: String,
|
|
) -> Result<PublicWorkDetailEntryRecord, SpacetimeClientError> {
|
|
let public_work_code = public_work_code.trim().to_string();
|
|
if public_work_code.is_empty() {
|
|
return Err(SpacetimeClientError::validation_failed(
|
|
"publicWorkCode 不能为空",
|
|
));
|
|
}
|
|
|
|
self.read_after_connect("get_public_work_detail_by_code", move |connection| {
|
|
let recent_play_counts = public_work_recent_play_counts_by_source(connection);
|
|
let entry = connection
|
|
.db()
|
|
.public_work_detail_entry()
|
|
.iter()
|
|
.find(|entry| {
|
|
entry
|
|
.public_work_code
|
|
.eq_ignore_ascii_case(&public_work_code)
|
|
})
|
|
.ok_or_else(|| SpacetimeClientError::Procedure("公开作品不存在".to_string()))?;
|
|
let recent_play_count_7d = recent_play_counts
|
|
.get(&(entry.source_type.clone(), entry.profile_id.clone()))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
|
|
Ok(map_public_work_gallery_entry_to_detail_entry(
|
|
entry,
|
|
recent_play_count_7d,
|
|
))
|
|
})
|
|
.await
|
|
}
|
|
|
|
pub async fn get_public_work_detail_by_source_profile(
|
|
&self,
|
|
source_type: String,
|
|
profile_id: String,
|
|
) -> Result<PublicWorkDetailEntryRecord, SpacetimeClientError> {
|
|
let source_type = source_type.trim().to_string();
|
|
let profile_id = profile_id.trim().to_string();
|
|
if source_type.is_empty() || profile_id.is_empty() {
|
|
return Err(SpacetimeClientError::validation_failed(
|
|
"sourceType 和 profileId 不能为空",
|
|
));
|
|
}
|
|
|
|
self.read_after_connect(
|
|
"get_public_work_detail_by_source_profile",
|
|
move |connection| {
|
|
let recent_play_counts = public_work_recent_play_counts_by_source(connection);
|
|
let entry = connection
|
|
.db()
|
|
.public_work_detail_entry()
|
|
.iter()
|
|
.find(|entry| {
|
|
entry.source_type == source_type && entry.profile_id == profile_id
|
|
})
|
|
.ok_or_else(|| SpacetimeClientError::Procedure("公开作品不存在".to_string()))?;
|
|
let recent_play_count_7d = recent_play_counts
|
|
.get(&(entry.source_type.clone(), entry.profile_id.clone()))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
|
|
Ok(map_public_work_gallery_entry_to_detail_entry(
|
|
entry,
|
|
recent_play_count_7d,
|
|
))
|
|
},
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
|
|
fn sort_public_work_gallery_entries(entries: &mut [PublicWorkGalleryEntry]) {
|
|
entries.sort_by(|left, right| {
|
|
right
|
|
.sort_time_micros
|
|
.cmp(&left.sort_time_micros)
|
|
.then_with(|| left.source_type.cmp(&right.source_type))
|
|
.then_with(|| left.profile_id.cmp(&right.profile_id))
|
|
});
|
|
}
|
|
|
|
fn sort_public_work_detail_entries(entries: &mut [PublicWorkDetailEntry]) {
|
|
entries.sort_by(|left, right| {
|
|
right
|
|
.sort_time_micros
|
|
.cmp(&left.sort_time_micros)
|
|
.then_with(|| left.source_type.cmp(&right.source_type))
|
|
.then_with(|| left.profile_id.cmp(&right.profile_id))
|
|
});
|
|
}
|
|
|
|
fn public_work_recent_play_counts_by_source(
|
|
connection: &DbConnection,
|
|
) -> HashMap<(String, String), u32> {
|
|
let current_day = current_public_work_day();
|
|
let first_day = current_day - (PUBLIC_WORK_RECENT_PLAY_WINDOW_DAYS - 1);
|
|
let mut counts = HashMap::new();
|
|
|
|
for row in connection.db().public_work_play_daily_stat().iter() {
|
|
if row.played_day < first_day || row.played_day > current_day {
|
|
continue;
|
|
}
|
|
let entry = counts
|
|
.entry((row.source_type, row.profile_id))
|
|
.or_insert(0_u32);
|
|
*entry = entry.saturating_add(row.play_count);
|
|
}
|
|
|
|
counts
|
|
}
|