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 6364d06..532ec20 100644 Binary files a/backend/routes/__pycache__/videos.cpython-312.pyc and b/backend/routes/__pycache__/videos.cpython-312.pyc differ 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 483cf60..e53d09f 100644 Binary files a/backend/services/__pycache__/video_service.cpython-312.pyc and b/backend/services/__pycache__/video_service.cpython-312.pyc differ diff --git a/backend/services/video_service.py b/backend/services/video_service.py index 2b5e08b..e8164da 100644 --- a/backend/services/video_service.py +++ b/backend/services/video_service.py @@ -48,5 +48,17 @@ def update_file_path(db: Session, video_id: int, path: str): db.commit() +def delete_not_downloaded(db: Session, profile_id: int) -> 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