From: Christian Heller <c.heller@plomlompom.de>
Date: Sat, 23 Nov 2024 08:19:56 +0000 (+0100)
Subject: Add file deletion via "delete" flag.
X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/decks/reset_cookie?a=commitdiff_plain;h=10ba830cdabc8d27f722a7f7dfbfacf22c88df1a;p=ytplom

Add file deletion via "delete" flag.
---

diff --git a/templates/video.tmpl b/templates/video.tmpl
index a0142bb..bcdaabb 100644
--- a/templates/video.tmpl
+++ b/templates/video.tmpl
@@ -5,7 +5,7 @@
 <table>
 <tr><th>path:</th><td>{{file.rel_path}}</td></tr>
 <tr><th>YouTube ID:</th><td><a href="/yt_video/{{file.yt_id}}">{{file.yt_id}}</a></tr>
-<tr><th>present:</th><td>{% if file.missing %}no{% else %}<a href="/dl/{{file.yt_id}}">yes</a>{% endif %}</td></tr>
+<tr><th>present:</th><td>{% if file.present %}<a href="/dl/{{file.yt_id}}">yes</a>{% else %}no{% endif %}</td></tr>
 </table>
 <form action="/video/{{file.yt_id}}" method="POST" />
 {% for flag_name in flag_names %}
diff --git a/ytplom/misc.py b/ytplom/misc.py
index 9e547ec..5d7a2f0 100644
--- a/ytplom/misc.py
+++ b/ytplom/misc.py
@@ -118,9 +118,7 @@ CREATE TABLE files (
 '''
 
 VIDEO_FLAGS: dict[FlagName, FlagsInt] = {
-  FlagName('foo'): FlagsInt(1 << 0),
-  FlagName('bar'): FlagsInt(1 << 1),
-  FlagName('baz'): FlagsInt(1 << 2)
+  FlagName('delete'): FlagsInt(1 << 62)
 }
 
 
@@ -305,7 +303,6 @@ class VideoFile(DbData):
         self.rel_path = rel_path
         self.yt_id = yt_id
         self.flags = flags
-        self.missing = False
 
     @classmethod
     def get_by_yt_id(cls, conn: DatabaseConnection, yt_id: YoutubeId) -> Self:
@@ -316,10 +313,32 @@ class VideoFile(DbData):
             raise NotFoundException
         return cls._from_table_row(row)
 
+    @property
+    def full_path(self) -> PathStr:
+        """Return self.rel_path suffixed under PATH_DOWNLOADS."""
+        return PathStr(path_join(PATH_DOWNLOADS, self.rel_path))
+
+    @property
+    def present(self) -> bool:
+        """Return if file exists in filesystem."""
+        return path_exists(self.full_path)
+
+    @property
+    def missing(self) -> bool:
+        """Return if file absent despite absence of 'delete' flag."""
+        return not (self.flag_set(FlagName('delete')) or self.present)
+
     def flag_set(self, flag_name: FlagName) -> bool:
         """Return if flag of flag_name is set in self.flags."""
         return self.flags & VIDEO_FLAGS[flag_name]
 
+    def ensure_absence_if_deleted(self) -> None:
+        """If 'delete' flag set, ensure no actual file in filesystem."""
+        if self.flag_set(FlagName('delete')) and path_exists(self.full_path):
+            print(f'SYNC: {self.rel_path} set "delete", '
+                  'removing from filesystem.')
+            os_remove(self.full_path)
+
 
 class QuotaLog(DbData):
     """Collects API access quota costs."""
@@ -509,8 +528,7 @@ class DownloadsDb:
                 file.save(conn)
         self._files = VideoFile.get_all(conn)
         for file in self._files:
-            if not isfile(path_join(file.rel_path)):
-                file.missing = True
+            file.ensure_absence_if_deleted()
         chdir(old_cwd)
         conn.commit_close()
 
@@ -533,8 +551,7 @@ class DownloadsDb:
     def ids_to_paths(self) -> DownloadsIndex:
         """Return mapping YoutubeIds:paths of files downloaded to them."""
         self._sync_db()
-        return {f.yt_id: PathStr(path_join(PATH_DOWNLOADS, f.rel_path))
-                for f in self._files}
+        return {f.yt_id: f.full_path for f in self._files}
 
     @property
     def ids_unfinished(self) -> set[YoutubeId]:
@@ -638,6 +655,7 @@ class TaskHandler(BaseHTTPRequestHandler):
             file.flags |= VIDEO_FLAGS[flag_name]
         file.save(conn)
         conn.commit_close()
+        file.ensure_absence_if_deleted()
         self._send_http(headers=[('Location', f'/video/{yt_id}')], code=302)
 
     def _post_query(self, query_txt: QueryText) -> None: