Banners, additional images, and files upload to Dropbox.
Dropbox file IDs are saved with the article in Supabase. Banners appear in thumbnails and behind the article title/subtitle. Additional images and files appear below the article text.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
"""Migrate referenced local article media; originals are retained as backups."""
|
||||
import argparse
|
||||
import json
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from backend import main, dropbox_storage
|
||||
|
||||
|
||||
def migrate(apply=False):
|
||||
records = main.article_records()
|
||||
media = {item["url"]: item for post in records for item in [post.get("banner"), *(post.get("attachments") or [])] if item}
|
||||
local = [item for item in media.values() if item.get("storage") != "dropbox"]
|
||||
print(f"{len(local)} local media references across {len(records)} articles.")
|
||||
if not apply:
|
||||
print("Preview only. Use --apply to upload files and update article metadata.")
|
||||
return
|
||||
dropbox_storage.get_dropbox() # Fail before modifying anything if not configured.
|
||||
converted = {}
|
||||
for item in local:
|
||||
upload_id = item["url"].rsplit("/", 1)[-1]
|
||||
stored = main.uploaded_media(upload_id)
|
||||
if stored.get("storage") != "dropbox":
|
||||
data = (main.UPLOAD_DIR / upload_id).read_bytes()
|
||||
stored = {**stored, "storage": "dropbox", "dropbox_file_id": dropbox_storage.upload(data, upload_id, stored["name"])}
|
||||
main.save_media_metadata(upload_id, stored)
|
||||
# Keep old URLs working on this server too; retain the original bytes.
|
||||
(main.UPLOAD_DIR / f"{upload_id}.json").write_text(json.dumps(stored), encoding="utf-8")
|
||||
converted[item["url"]] = stored
|
||||
client = main.get_supabase()
|
||||
for post in records:
|
||||
banner = post.get("banner")
|
||||
attachments = post.get("attachments") or []
|
||||
replacement = {
|
||||
"banner": converted.get(banner["url"], banner) if banner else None,
|
||||
"attachments": [converted.get(item["url"], item) for item in attachments],
|
||||
}
|
||||
if replacement == {"banner": banner, "attachments": attachments}:
|
||||
continue
|
||||
if client is not None:
|
||||
result = client.table(main.articles_table()).update(replacement).eq("slug", post["slug"]).execute()
|
||||
if not result.data:
|
||||
raise RuntimeError("An article could not be updated. Retry the migration.")
|
||||
else:
|
||||
with main.POSTS_LOCK:
|
||||
latest = json.loads(main.POSTS_PATH.read_text(encoding="utf-8"))
|
||||
for current in latest:
|
||||
if current["slug"] == post["slug"]:
|
||||
current.update(replacement)
|
||||
main.save_local_posts(latest)
|
||||
print(f"Updated {len(converted)} media references. Original local files were retained.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--apply", action="store_true")
|
||||
arguments = parser.parse_args()
|
||||
load_dotenv(main.BASE_DIR / ".env")
|
||||
migrate(arguments.apply)
|
||||
Reference in New Issue
Block a user