feat: Allow deleting all __bad__ with a single button (#98)

This commit is contained in:
iPromKnight
2025-07-04 20:13:12 +01:00
committed by GitHub
parent c7b07137c5
commit f656b7e4e2
2 changed files with 72 additions and 20 deletions

View File

@@ -22,6 +22,8 @@ import (
"github.com/sirrobot01/decypharr/pkg/version" "github.com/sirrobot01/decypharr/pkg/version"
) )
const DeleteAllBadTorrentKey = "DELETE_ALL_BAD_TORRENTS"
type Handler struct { type Handler struct {
Name string Name string
logger zerolog.Logger logger zerolog.Logger
@@ -308,7 +310,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.handlePropfind(w, r) h.handlePropfind(w, r)
return return
case "DELETE": case "DELETE":
if err := h.handleIDDelete(w, r); err == nil { if err := h.handleDelete(w, r); err == nil {
return return
} }
// fallthrough to default // fallthrough to default
@@ -394,6 +396,7 @@ func (h *Handler) serveDirectory(w http.ResponseWriter, r *http.Request, file we
URLBase string URLBase string
IsBadPath bool IsBadPath bool
CanDelete bool CanDelete bool
DeleteAllBadTorrentKey string
}{ }{
Path: cleanPath, Path: cleanPath,
ParentPath: parentPath, ParentPath: parentPath,
@@ -402,6 +405,7 @@ func (h *Handler) serveDirectory(w http.ResponseWriter, r *http.Request, file we
URLBase: h.URLBase, URLBase: h.URLBase,
IsBadPath: isBadPath, IsBadPath: isBadPath,
CanDelete: canDelete, CanDelete: canDelete,
DeleteAllBadTorrentKey: DeleteAllBadTorrentKey,
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
@@ -534,8 +538,8 @@ func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// handleDelete deletes a torrent from using id // handleDelete deletes a torrent by id, or all bad torrents if the id is DeleteAllBadTorrentKey
func (h *Handler) handleIDDelete(w http.ResponseWriter, r *http.Request) error { func (h *Handler) handleDelete(w http.ResponseWriter, r *http.Request) error {
cleanPath := path.Clean(r.URL.Path) // Remove any leading slashes cleanPath := path.Clean(r.URL.Path) // Remove any leading slashes
_, torrentId := path.Split(cleanPath) _, torrentId := path.Split(cleanPath)
@@ -543,7 +547,15 @@ func (h *Handler) handleIDDelete(w http.ResponseWriter, r *http.Request) error {
return os.ErrNotExist return os.ErrNotExist
} }
cachedTorrent := h.cache.GetTorrent(torrentId) if torrentId == DeleteAllBadTorrentKey {
return h.handleDeleteAll(w)
}
return h.handleDeleteById(w, torrentId)
}
func (h *Handler) handleDeleteById(w http.ResponseWriter, tId string) error {
cachedTorrent := h.cache.GetTorrent(tId)
if cachedTorrent == nil { if cachedTorrent == nil {
return os.ErrNotExist return os.ErrNotExist
} }
@@ -552,3 +564,22 @@ func (h *Handler) handleIDDelete(w http.ResponseWriter, r *http.Request) error {
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
return nil return nil
} }
func (h *Handler) handleDeleteAll(w http.ResponseWriter) error {
badTorrents := h.cache.GetListing("__bad__")
if len(badTorrents) == 0 {
http.Error(w, "No bad torrents to delete", http.StatusNotFound)
return nil
}
for _, fi := range badTorrents {
tName := strings.TrimSpace(strings.SplitN(fi.Name(), "||", 2)[0])
t := h.cache.GetTorrentByName(tName)
if t != nil {
h.cache.OnRemove(t.Id)
}
}
w.WriteHeader(http.StatusNoContent)
return nil
}

View File

@@ -106,6 +106,19 @@
</li> </li>
{{- end}} {{- end}}
{{$isBadPath := hasSuffix .Path "__bad__"}} {{$isBadPath := hasSuffix .Path "__bad__"}}
{{- if and $isBadPath (gt (len .Children) 0) }}
<li>
<span class="file-number">&nbsp;</span>
<span class="file-name">&nbsp;</span>
<span class="file-info">&nbsp;</span>
<button
class="delete-btn"
id="delete-all-btn"
data-name="{{.DeleteAllBadTorrentKey}}">
Delete All
</button>
</li>
{{- end}}
{{- range $i, $file := .Children}} {{- range $i, $file := .Children}}
<li class="{{if $isBadPath}}disabled{{end}}"> <li class="{{if $isBadPath}}disabled{{end}}">
<a {{ if not $isBadPath}}href="{{urlpath (printf "%s/%s" $.Path $file.Name)}}"{{end}}> <a {{ if not $isBadPath}}href="{{urlpath (printf "%s/%s" $.Path $file.Name)}}"{{end}}>
@@ -118,7 +131,7 @@
</a> </a>
{{- if and $.CanDelete }} {{- if and $.CanDelete }}
<button <button
class="delete-btn" class="delete-btn delete-with-id-btn"
data-name="{{$file.Name}}" data-name="{{$file.Name}}"
data-path="{{printf "%s/%s" $.Path $file.ID}}"> data-path="{{printf "%s/%s" $.Path $file.ID}}">
Delete Delete
@@ -128,7 +141,7 @@
{{- end}} {{- end}}
</ul> </ul>
<script> <script>
document.querySelectorAll('.delete-btn').forEach(btn=>{ document.querySelectorAll('.delete-with-id-btn').forEach(btn=>{
btn.addEventListener('click', ()=>{ btn.addEventListener('click', ()=>{
let p = btn.getAttribute('data-path'); let p = btn.getAttribute('data-path');
let name = btn.getAttribute('data-name'); let name = btn.getAttribute('data-name');
@@ -137,6 +150,14 @@
.then(_=>location.reload()); .then(_=>location.reload());
}); });
}); });
const deleteAllButton = document.getElementById('delete-all-btn');
deleteAllButton.addEventListener('click', () => {
let p = deleteAllButton.getAttribute('data-name');
if (!confirm('Delete all entries marked Bad?')) return;
fetch(p, { method: 'DELETE' })
.then(_=>location.reload());
});
</script> </script>
</body> </body>
</html> </html>