From 375169f496a75a2010669a9ee4fb753eaf1bc545 Mon Sep 17 00:00:00 2001 From: Marek Date: Sun, 5 Apr 2026 22:20:51 +0200 Subject: [PATCH] update --- .../main/java/com/youtubeapp/data/VideoApi.kt | 3 +++ .../com/youtubeapp/data/VideoRepository.kt | 5 +++++ .../youtubeapp/ui/navigation/AppNavigation.kt | 4 ++++ .../youtubeapp/ui/viewmodel/VideoViewModel.kt | 8 ++++++++ .../routes/__pycache__/videos.cpython-312.pyc | Bin 6181 -> 6546 bytes backend/routes/videos.py | 6 ++++++ .../__pycache__/video_service.cpython-312.pyc | Bin 3917 -> 4645 bytes backend/services/video_service.py | 12 ++++++++++++ features.md | 3 ++- 9 files changed, 40 insertions(+), 1 deletion(-) diff --git a/app/frontend/src/main/java/com/youtubeapp/data/VideoApi.kt b/app/frontend/src/main/java/com/youtubeapp/data/VideoApi.kt index 6c91b22..fa23baf 100644 --- a/app/frontend/src/main/java/com/youtubeapp/data/VideoApi.kt +++ b/app/frontend/src/main/java/com/youtubeapp/data/VideoApi.kt @@ -15,6 +15,9 @@ interface VideoApi { @POST("videos/{id}/download") suspend fun triggerDownload(@Path("id") id: Int): Map + @retrofit2.http.DELETE("videos") + suspend fun deleteNotDownloaded(@Query("profile_id") profileId: Int): Map + @GET("profiles") suspend fun getProfiles(): List } diff --git a/app/frontend/src/main/java/com/youtubeapp/data/VideoRepository.kt b/app/frontend/src/main/java/com/youtubeapp/data/VideoRepository.kt index c9dddb4..82d8fd3 100644 --- a/app/frontend/src/main/java/com/youtubeapp/data/VideoRepository.kt +++ b/app/frontend/src/main/java/com/youtubeapp/data/VideoRepository.kt @@ -13,6 +13,11 @@ class VideoRepository(private val api: VideoApi = ApiClient.api) { response["status"] ?: "unknown" } + suspend fun deleteNotDownloaded(profileId: Int): Result = runCatching { + val response = api.deleteNotDownloaded(profileId) + response["deleted"] ?: 0 + } + suspend fun getProfiles(): Result> = runCatching { api.getProfiles() } fun getStreamUrl(videoId: Int): String = "${ApiClient.BASE_URL}videos/$videoId/stream" diff --git a/app/frontend/src/main/java/com/youtubeapp/ui/navigation/AppNavigation.kt b/app/frontend/src/main/java/com/youtubeapp/ui/navigation/AppNavigation.kt index dff5231..1148d47 100644 --- a/app/frontend/src/main/java/com/youtubeapp/ui/navigation/AppNavigation.kt +++ b/app/frontend/src/main/java/com/youtubeapp/ui/navigation/AppNavigation.kt @@ -2,6 +2,7 @@ package com.youtubeapp.ui.navigation import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DeleteSweep import androidx.compose.material.icons.filled.Download import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.VideoLibrary @@ -64,6 +65,9 @@ fun AppNavigation() { TopAppBar( title = { Text("YouTube App") }, actions = { + IconButton(onClick = { viewModel.deleteNotDownloaded() }) { + Icon(Icons.Default.DeleteSweep, contentDescription = "Aufraeumen") + } IconButton(onClick = { showProfileMenu = true }) { Icon(Icons.Default.Person, contentDescription = "Profil") } diff --git a/app/frontend/src/main/java/com/youtubeapp/ui/viewmodel/VideoViewModel.kt b/app/frontend/src/main/java/com/youtubeapp/ui/viewmodel/VideoViewModel.kt index 94aba13..5d5b117 100644 --- a/app/frontend/src/main/java/com/youtubeapp/ui/viewmodel/VideoViewModel.kt +++ b/app/frontend/src/main/java/com/youtubeapp/ui/viewmodel/VideoViewModel.kt @@ -126,6 +126,14 @@ class VideoViewModel : ViewModel() { } } + fun deleteNotDownloaded() { + val profileId = _state.value.selectedProfileId ?: return + viewModelScope.launch { + repository.deleteNotDownloaded(profileId) + loadAllVideos() + } + } + fun deleteLocalVideo(videoId: Int) { localStorage?.deleteLocalFile(videoId) _state.value = _state.value.copy(downloadStatus = "Lokal gelöscht") diff --git a/backend/routes/__pycache__/videos.cpython-312.pyc b/backend/routes/__pycache__/videos.cpython-312.pyc index 6364d062ff478d543e714fefb601494362420e86..532ec201b1fe913f0f35c83d79e20c0d7d36d6e0 100644 GIT binary patch delta 784 zcmZ9KO=uHA6vuZayRB`u$u`@Vq%~%f*0x)kv{5M~wdtu;s#Zaz8l*+Dn>LVU%VeV{ zf>i`PNs~Ex5k*kqp|Te*g3^m1LTe8-3mybPyhyco^-bbObz%PVX5Me!d-G-=4wetN zUbnO~bMS>%-)0l;lFN_gpZ3@YP0$a#>~>cWb8;N!^d`+uXRt4TwKiSRJi05xYk`|W zr4DeZF8Uq$P&+UIU&kL}&kkZAy@TVZgTBCC)D5-|g%~~XmsWPrJ&?0O3u}=%^u$%c z^)#toy_YUyFLgNjT03{p>Sd&MSxLuyqd%7Z1=o)7pbi+@L-c)f{F;WY;w(DJsd&n6 z)byNg>Y9p)1cdFauV?dyIjb3$@;T$Y23`k=ftLgrBBYIC-Yl?yilUHy<{17heP9$q zAWPgwF|a8PtcwFHcx7@!99tTHCwiBQYmLs}8Xw%|tOw0s5E`LnaY#4{CkE*o@ggP( zYrJIvIY(Kiuu82* z{)t0BdAj8jjGY3x!p9aC55m2VQ$-F%C)hr_6FJMI3B(r6teMkQp8S_@n&#xNFayYG zT9$911ogJvRWHDL4n{!+f$KZ{n@)AzsXmHqIHPNPlq6tZ?IVY+YMTq4vK#8HuJ?{L zfUx2T3v0U8wn?oO_j7HNJ8f?Y)=YV$-vUZ*1Cja9G~LV9{aUXP%Y!6PO*hI{*Lx delta 542 zcmbPaywrg2G%qg~0}yDfyp);GH<3?*QD~$3EkuRW)DCJb?EPGT9AYO_zSd%zHlMIq3mC19M43P|!Ly}WvVn}66kxx-bXI#U# znh9cblv=7U)dUrhl&e=VYAS7>!kodr`5gCaMn<#AyLipG+=1G(fVens z@_rG`$;x~lOrIGx=knz;a$5j}i$LBivfBKVKZcRfeX^5aJEPO&Q-VsOW*~7%5TOYo zLO?|DWJV!H)-WK`e6qUGL`ILzJB7Sa%$dwDq9*JEQtJgIs#x@L3rsYbio7R#h{)?Y zfy9|XL@0>h1QNGcOEODxQZ-qM(CiDIJViv2H43Q2fATJoCPt6RwxY9HgzqBN^s0gHSB|{NNSCI}# k1&2*;eoARhs$Ee5kjn_f#UB_qCyNU(PF^kXm<6N|0BKfoyZ`_I diff --git a/backend/routes/videos.py b/backend/routes/videos.py index ab6f1de..934d0d1 100644 --- a/backend/routes/videos.py +++ b/backend/routes/videos.py @@ -39,6 +39,12 @@ def get_downloaded_videos(profile_id: Optional[int] = Query(None), db: Session = return [VideoResponse.from_model(v) for v in videos] +@router.delete("") +def delete_not_downloaded(profile_id: int = Query(...), db: Session = Depends(get_db)): + count = video_service.delete_not_downloaded(db, profile_id) + return {"deleted": count} + + @router.post("/{video_id}/download") def trigger_download(video_id: int, db: Session = Depends(get_db)): video = video_service.get_video(db, video_id) diff --git a/backend/services/__pycache__/video_service.cpython-312.pyc b/backend/services/__pycache__/video_service.cpython-312.pyc index 483cf6078d445eed81c413520366b7fce716108c..e53d09f33bb83f0c4eb11f2c7ec441326e0404cb 100644 GIT binary patch delta 583 zcmXw#%WG3X6vk)nbM8&&=1tN>Lu+bl7Oqkd3X)ANgo+zoltKy8nQ9~?GKq?i&{P8& zDkR~$h#*=8q0o)u#(kIKA{I$V1^o|tAqBUd@p0h(zVAD8<}lnZsdsbEXG(1Z6*>G` zd}a2WIQDuAD>%~YCQZAgulpF-&5Xq@W^ilEV4;?_9%LHFkZrC`!`&^7g`pdINHWon z1e2+lB3J$^6I6w7avQr%TWAa&VE3BIvEuIO=jIzqE&6}7t{mXMzMGhX5~UMN>;1y*@bE>&(a z&ctOnluN6R08KQa{?1x^?K$5q3~72m)87g0_}l&=Ne)P|zkEbyWyfhdLy{Pf#LG*s zmtHLGCkDyv5m}t*s$={zkZJF1KIWc@bl)jKG|)A6SLd5oj)SqM`iR&at8I19el`jx mIM~1CA&~dkKk_L%k;#i=obJaw1hRKyf8ou>sk9;mSAPSYt%`I2 delta 115 zcmZ3ga#oJ-G%qg~0}x2Byp);FHjz()@yT3DmFQ-I85QMOdBRAxz_ zx-^y)p%#`X!AcHIk int: + videos = db.query(Video).filter( + Video.file_path.is_(None), + Video.profiles.any(Profile.id == profile_id), + ).all() + count = len(videos) + for video in videos: + db.delete(video) + db.commit() + return count + + def get_all_profiles(db: Session) -> list[Profile]: return db.query(Profile).all() diff --git a/features.md b/features.md index c20abd2..49a04e6 100644 --- a/features.md +++ b/features.md @@ -11,4 +11,5 @@ - Klick auf Startet startet den Stream über den Server mit den Standard Video-Controls und einem Zurück-Button - Klick auf Download lädt das Video herunter und wird lokal auf dem Client gespeichert - Klick auf Icon zeigt verfügbare Profile -- Das ausgewählte Profil wird persistiert und bestimmt welche Videos angezeigt werden \ No newline at end of file +- Das ausgewählte Profil wird persistiert und bestimmt welche Videos angezeigt werden +- Klick auf Icon löscht alle nicht heruntergeladenen Videos vom aktuellen Profil \ No newline at end of file