feat: add download tracking endpoints (sections 4.1, 4.2, 4.3, 4.4)
This commit is contained in:
@@ -577,6 +577,224 @@ func parseUUID(s string) (uuid.UUID, error) {
|
||||
return uuid.Parse(s)
|
||||
}
|
||||
|
||||
func (h *Handlers) ListQueue(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
var status *string
|
||||
if s := r.URL.Query().Get("status"); s != "" {
|
||||
status = &s
|
||||
}
|
||||
|
||||
items, err := h.DB.ListDownloadQueue(r.Context(), status)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"items": items,
|
||||
"total": len(items),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handlers) GetQueueItem(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
id, err := parseUUID(idStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid ID")
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.DB.GetDownloadQueueItem(r.Context(), id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "queue item not found")
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, item)
|
||||
}
|
||||
|
||||
func (h *Handlers) AddToQueue(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Title string `json:"title"`
|
||||
TorrentHash *string `json:"torrent_hash"`
|
||||
Size int64 `json:"size"`
|
||||
Indexer *string `json:"indexer"`
|
||||
AlbumID *string `json:"album_id"`
|
||||
ArtistID *string `json:"artist_id"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
var albumID, artistID *uuid.UUID
|
||||
if req.AlbumID != nil {
|
||||
if id, err := parseUUID(*req.AlbumID); err == nil {
|
||||
albumID = &id
|
||||
}
|
||||
}
|
||||
if req.ArtistID != nil {
|
||||
if id, err := parseUUID(*req.ArtistID); err == nil {
|
||||
artistID = &id
|
||||
}
|
||||
}
|
||||
|
||||
id, err := h.DB.AddToDownloadQueue(r.Context(), req.Title, req.Size, req.TorrentHash, req.Indexer, albumID, artistID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
item, _ := h.DB.GetDownloadQueueItem(r.Context(), id)
|
||||
writeJSON(w, http.StatusOK, item)
|
||||
}
|
||||
|
||||
func (h *Handlers) UpdateQueueItem(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
id, err := parseUUID(idStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Status *string `json:"status"`
|
||||
ErrorMessage *string `json:"error_message"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Status != nil {
|
||||
if *req.Status == "failed" && req.ErrorMessage != nil {
|
||||
services.HandleFailedDownload(r.Context(), h.DB, id, *req.ErrorMessage)
|
||||
} else {
|
||||
if err := h.DB.UpdateDownloadQueueStatus(r.Context(), id, *req.Status, req.ErrorMessage); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if *req.Status == "completed" {
|
||||
item, _ := h.DB.GetDownloadQueueItem(r.Context(), id)
|
||||
if item != nil && item.AlbumID != nil {
|
||||
h.DB.RemoveFromWantedAlbums(r.Context(), *item.AlbumID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item, err := h.DB.GetDownloadQueueItem(r.Context(), id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "queue item not found")
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, item)
|
||||
}
|
||||
|
||||
func (h *Handlers) DeleteQueueItem(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
id, err := parseUUID(idStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid ID")
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.DB.GetDownloadQueueItem(r.Context(), id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "queue item not found")
|
||||
return
|
||||
}
|
||||
|
||||
if item.TorrentHash != nil && h.TorrentService.IsConfigured() {
|
||||
h.TorrentService.RemoveTorrent(r.Context(), *item.TorrentHash, false)
|
||||
}
|
||||
|
||||
if err := h.DB.DeleteDownloadQueueItem(r.Context(), id); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]any{"deleted": true})
|
||||
}
|
||||
|
||||
func (h *Handlers) SyncQueue(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := services.SyncDownloadQueue(r.Context(), h.DB, h.TorrentService)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (h *Handlers) BlocklistQueueItem(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
id, err := parseUUID(idStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid ID")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := services.BlocklistAndRemove(r.Context(), h.DB, h.TorrentService, id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (h *Handlers) QueueStats(w http.ResponseWriter, r *http.Request) {
|
||||
if h.DB == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "database not connected")
|
||||
return
|
||||
}
|
||||
|
||||
stats, err := h.DB.GetDownloadQueueStats(r.Context())
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, stats)
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, v any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
|
||||
Reference in New Issue
Block a user