home · contact · privacy
Add file deletion via "delete" flag.
authorChristian Heller <c.heller@plomlompom.de>
Sat, 23 Nov 2024 08:19:56 +0000 (09:19 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 23 Nov 2024 08:19:56 +0000 (09:19 +0100)
templates/video.tmpl
ytplom/misc.py

index a0142bbe3a41e071cdb97a53264b3f6988e7ed9c..bcdaabb00375a20db33b7ce2dec098418e8b5d9d 100644 (file)
@@ -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 %}
index 9e547eca30119fa9c19e5c59d5fea6a6bb984089..5d7a2f09785430e58308a9334d178a965f25f73a 100644 (file)
@@ -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: