Library sorting: download-date sort + grouped sort options (both UIs)
Add "download date" sorting (file mtime, distinct from upload date) plus a broader set of options. Web select is now grouped via <optgroup>; desktop gains SortMode::DownloadDesc/DownloadAsc/ChannelAsc with matching arms and toolbar entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
015d03751c
commit
8b2578783a
2 changed files with 48 additions and 9 deletions
23
src/app.rs
23
src/app.rs
|
|
@ -71,6 +71,9 @@ enum SortMode {
|
|||
SizeDesc,
|
||||
DateDesc,
|
||||
DateAsc,
|
||||
DownloadDesc,
|
||||
DownloadAsc,
|
||||
ChannelAsc,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
|
|
@ -883,6 +886,19 @@ impl App {
|
|||
}
|
||||
});
|
||||
}
|
||||
SortMode::DownloadDesc => {
|
||||
// Most-recently-downloaded first (file mtime); missing → end.
|
||||
cards.sort_by(|a, b| b.mtime_unix.unwrap_or(0).cmp(&a.mtime_unix.unwrap_or(0)));
|
||||
}
|
||||
SortMode::DownloadAsc => {
|
||||
cards.sort_by(|a, b| a.mtime_unix.unwrap_or(u64::MAX).cmp(&b.mtime_unix.unwrap_or(u64::MAX)));
|
||||
}
|
||||
SortMode::ChannelAsc => {
|
||||
cards.sort_by(|a, b| {
|
||||
a.channel_name.to_lowercase().cmp(&b.channel_name.to_lowercase())
|
||||
.then_with(|| a.title.to_lowercase().cmp(&b.title.to_lowercase()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cards
|
||||
|
|
@ -4131,13 +4147,16 @@ impl App {
|
|||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DateDesc, "Newest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DateAsc, "Oldest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::SizeDesc, "Largest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::SizeAsc, "Smallest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DurationDesc, "Longest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DurationAsc, "Shortest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::ChannelAsc, "Channel");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::Title, "Title");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DateAsc, "Oldest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DateDesc, "Newest");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DownloadAsc, "Oldest DL");
|
||||
ui.selectable_value(&mut self.sort_mode, SortMode::DownloadDesc, "Recent DL");
|
||||
ui.label(egui::RichText::new("Sort:").weak());
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -216,13 +216,29 @@
|
|||
<h1>yt-offline</h1>
|
||||
<input type="search" id="search" placeholder="Filter…" oninput="saveUiState();renderGrid()">
|
||||
<select id="sort" onchange="saveUiState();renderGrid()">
|
||||
<optgroup label="Download date">
|
||||
<option value="dl-desc">Recently downloaded</option>
|
||||
<option value="dl-asc">Oldest download</option>
|
||||
</optgroup>
|
||||
<optgroup label="Upload date">
|
||||
<option value="date-desc">Newest</option>
|
||||
<option value="date-asc">Oldest</option>
|
||||
<option value="title">Title</option>
|
||||
</optgroup>
|
||||
<optgroup label="Title">
|
||||
<option value="title">Title (A→Z)</option>
|
||||
<option value="title-desc">Title (Z→A)</option>
|
||||
</optgroup>
|
||||
<optgroup label="Channel">
|
||||
<option value="channel">Channel (A→Z)</option>
|
||||
</optgroup>
|
||||
<optgroup label="Duration">
|
||||
<option value="dur-asc">Shortest</option>
|
||||
<option value="dur-desc">Longest</option>
|
||||
</optgroup>
|
||||
<optgroup label="Size">
|
||||
<option value="size-asc">Smallest</option>
|
||||
<option value="size-desc">Largest</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<span id="hdr-stats"></span>
|
||||
<button onclick="openSearch()" title="Search titles, descriptions & transcripts (f)">🔍</button>
|
||||
|
|
@ -617,6 +633,8 @@ function currentVideos(){
|
|||
for(const v of pool)
|
||||
if((!q||matchesSearch(v,ch?.name||v.channel,q))&&passesFilter(v))vids.push({...v,channel:ch.name});
|
||||
}
|
||||
if(sort==='dl-desc')vids.sort((a,b)=>(b.mtime_unix||0)-(a.mtime_unix||0));
|
||||
if(sort==='dl-asc')vids.sort((a,b)=>(a.mtime_unix||0)-(b.mtime_unix||0));
|
||||
if(sort==='date-desc')vids.sort((a,b)=>(b.upload_date||'').localeCompare(a.upload_date||''));
|
||||
if(sort==='date-asc')vids.sort((a,b)=>{const ax=a.upload_date||'',bx=b.upload_date||'';return ax.localeCompare(bx)});
|
||||
if(sort==='dur-asc')vids.sort((a,b)=>(a.duration_secs??0)-(b.duration_secs??0));
|
||||
|
|
@ -624,6 +642,8 @@ function currentVideos(){
|
|||
if(sort==='size-asc')vids.sort((a,b)=>(a.file_size??0)-(b.file_size??0));
|
||||
if(sort==='size-desc')vids.sort((a,b)=>(b.file_size??0)-(a.file_size??0));
|
||||
if(sort==='title')vids.sort((a,b)=>a.title.localeCompare(b.title));
|
||||
if(sort==='title-desc')vids.sort((a,b)=>b.title.localeCompare(a.title));
|
||||
if(sort==='channel')vids.sort((a,b)=>(a.channel||'').localeCompare(b.channel||'')||a.title.localeCompare(b.title));
|
||||
return vids;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue