mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-03 02:53:58 -06:00
Best quality format, password UX, mobile columns
Best quality format: - Synthetic 'bestvideo+bestaudio/best' entry added at top of format list when the best separate video stream exceeds the best pre-muxed format. Shows as 'Best quality (1920x1080)' in Video+Audio group. - YouTube typically only has 360p pre-muxed but 1080p+ as separate streams — users can now select full quality with auto-merge. - Only appears when there's actually a quality advantage vs pre-muxed. Password change UX: - Enter key on confirm password field submits the change - Auto-logout 1.5s after successful password change - User sees '✓ Password changed' before being redirected home Mobile table: - Status column hidden on mobile (<640px) alongside Progress - Only Name + Actions columns shown — clean two-column layout - Removed mobile-specific status badge font tweaks (column gone)
This commit is contained in:
parent
5da223c5f8
commit
3d778246ca
3 changed files with 50 additions and 11 deletions
|
|
@ -229,6 +229,47 @@ class DownloadService:
|
|||
key=lambda fi: _parse_resolution_height(fi.resolution),
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
# Add synthetic "best quality" entries at the top.
|
||||
# yt-dlp can merge separate video+audio streams for best quality,
|
||||
# but those don't appear as pre-muxed formats in the format list.
|
||||
best_video = None
|
||||
best_audio = None
|
||||
for f in formats_raw:
|
||||
vcodec = f.get("vcodec", "none")
|
||||
acodec = f.get("acodec", "none")
|
||||
height = f.get("height") or 0
|
||||
if vcodec and vcodec != "none" and height > 0:
|
||||
if best_video is None or height > (best_video.get("height") or 0):
|
||||
best_video = f
|
||||
if acodec and acodec != "none" and (vcodec == "none" or not vcodec):
|
||||
if best_audio is None:
|
||||
best_audio = f
|
||||
|
||||
if best_video:
|
||||
bv_height = best_video.get("height", 0)
|
||||
bv_res = f"{best_video.get('width', '?')}x{bv_height}"
|
||||
# Only add if the best separate video exceeds the best pre-muxed
|
||||
best_premuxed_height = 0
|
||||
for f in formats_raw:
|
||||
vc = f.get("vcodec", "none")
|
||||
ac = f.get("acodec", "none")
|
||||
if vc and vc != "none" and ac and ac != "none":
|
||||
h = f.get("height") or 0
|
||||
if h > best_premuxed_height:
|
||||
best_premuxed_height = h
|
||||
|
||||
if bv_height > best_premuxed_height:
|
||||
result.insert(0, FormatInfo(
|
||||
format_id="bestvideo+bestaudio/best",
|
||||
ext=best_video.get("ext", "webm"),
|
||||
resolution=bv_res,
|
||||
codec=best_video.get("vcodec"),
|
||||
format_note=f"Best quality ({bv_res})",
|
||||
vcodec=best_video.get("vcodec"),
|
||||
acodec="merged",
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
async def cancel(self, job_id: str) -> None:
|
||||
|
|
|
|||
|
|
@ -95,13 +95,15 @@ async function changePassword() {
|
|||
})
|
||||
|
||||
if (res.ok) {
|
||||
// Update stored credentials to use new password
|
||||
store.password = newPassword.value
|
||||
passwordChanged.value = true
|
||||
currentPassword.value = ''
|
||||
newPassword.value = ''
|
||||
confirmPassword.value = ''
|
||||
passwordChanged.value = true
|
||||
setTimeout(() => { passwordChanged.value = false }, 3000)
|
||||
// Auto-logout after 1.5s so user sees the success message
|
||||
setTimeout(() => {
|
||||
store.logout()
|
||||
router.push('/')
|
||||
}, 1500)
|
||||
} else {
|
||||
const data = await res.json()
|
||||
passwordError.value = data.detail || 'Failed to change password'
|
||||
|
|
@ -335,6 +337,7 @@ function formatFilesize(bytes: number | null): string {
|
|||
placeholder="Confirm new password"
|
||||
autocomplete="new-password"
|
||||
class="settings-input"
|
||||
@keydown.enter="changePassword"
|
||||
/>
|
||||
</div>
|
||||
<div class="settings-actions" style="margin-top: var(--space-sm);">
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ async function clearJob(jobId: string): Promise<void> {
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Mobile: hide speed, ETA, and progress columns */
|
||||
/* Mobile: hide speed, ETA, progress, and status columns */
|
||||
@media (max-width: 639px) {
|
||||
.hide-mobile {
|
||||
display: none;
|
||||
|
|
@ -527,7 +527,7 @@ async function clearJob(jobId: string): Promise<void> {
|
|||
}
|
||||
|
||||
.col-status {
|
||||
width: 75px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-progress {
|
||||
|
|
@ -553,11 +553,6 @@ async function clearJob(jobId: string): Promise<void> {
|
|||
.action-group {
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
font-size: 0.625rem;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Toast notification */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue