From 40fd555cd3fcff9d323cb0e42a287451083875ca Mon Sep 17 00:00:00 2001
From: Philipp Stadler <hello@phstadler.com>
Date: Sat, 20 Jul 2024 19:24:58 +0200
Subject: [PATCH] feat!: add apkg level resources

BREAKING CHANGE: new required field in .apkg-spec.yaml
---
 Makefile                                      |  2 +
 export_apkgs.py                               | 37 ++++++++++++-------
 test/fixtures/anki/.apkg-spec.yaml            |  4 +-
 test/fixtures/csv/.apkg-spec.yaml             |  4 +-
 .../csv_updated_content/.apkg-spec.yaml       |  4 +-
 version.txt                                   |  2 +-
 6 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/Makefile b/Makefile
index 9672b1e..df798b1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+.DELETE_ON_ERROR:
+
 ifneq ($(wildcard /bin/export_apkgs),)
 # no pipenv needed in container, deps are preinstalled globally
 PYTHON := $(shell python-libfaketime  | sed 's/export //') python3
diff --git a/export_apkgs.py b/export_apkgs.py
index 1b14265..b018d9b 100755
--- a/export_apkgs.py
+++ b/export_apkgs.py
@@ -69,6 +69,7 @@ class ApkgSpec(BaseModel):
         dict[Literal['import_csv'], ImportCsv]|
         dict[Literal['import_images'], ImportImages]
     ]
+    resource_paths: list[Path]
 
     @field_serializer('content_version')
     def dump_content_version(self, ver: Version):
@@ -129,6 +130,8 @@ class ApkgExporter:
         
         collection = self.empty_collection()
         name_to_ntid = self.add_note_types(collection)
+        # add content-level resources
+        self.add_resources(collection, self.spec.resource_paths)
         self.add_content(collection, name_to_ntid)
         collection.export_anki_package(
             # anki fails if this is just an apkg without a dir, but with ./ it's fine
@@ -171,19 +174,7 @@ class ApkgExporter:
 
             # start by adding resources
             with fake_time(format_time(template_spec.template_version)):
-                for resources_path in template_spec.resource_paths:
-                    # for resources generated using build,
-                    # {{BUILD_PREFIX}} may be used
-                    resources_path = Path(
-                        str(resources_path)
-                            .replace('{{BUILD_PREFIX}}', getenv('BUILD_PREFIX', '')
-                    ))
-                    for resource_path in resources_path.glob('*'):
-                        actual_path = col.media.add_file(resource_path)
-                        if actual_path != str(resource_path.name):
-                            raise Exception(f'resource was renamed by Anki from {resource_path} to {actual_path}, expected {resource_path.name} instead')
-                        # convince anki to include media in export
-                        self.resource_pseudo_usages += f'<img src="{actual_path}">'
+                self.add_resources(col, template_spec.resource_paths)
 
             # then add the card types with the html
             final_mod_date = template_spec.note_type.id
@@ -201,6 +192,26 @@ class ApkgExporter:
                 col.models.update_dict(note_type)
         return name_to_ntid
 
+    def add_resources(self, col: Collection, resource_paths: list[Path]):
+        for resources_path in resource_paths:
+            # for resources generated using build,
+            # {{BUILD_PREFIX}} may be used
+            resources_path = Path(
+                str(resources_path)
+                    .replace('{{BUILD_PREFIX}}', getenv('BUILD_PREFIX', '')
+            ))
+            if resources_path.is_file():
+                self.add_resource(col, resources_path)
+            elif resources_path.is_dir():
+                self.add_resources(col, resources_path.glob('*'))
+
+    def add_resource(self, col: Collection, resource_path: Path):
+        actual_path = col.media.add_file(resource_path)
+        if actual_path != str(resource_path.name):
+            raise Exception(f'resource was renamed by Anki from {resource_path} to {actual_path}, expected {resource_path.name} instead')
+        # convince anki to include media in export
+        self.resource_pseudo_usages += f'<img src="{actual_path}">'
+
     def add_note_type(self, col: Collection, spec: NoteType) -> NotetypeDict:
         name = spec.name
         fields = list(spec.fields)
diff --git a/test/fixtures/anki/.apkg-spec.yaml b/test/fixtures/anki/.apkg-spec.yaml
index 92ef748..24019f4 100644
--- a/test/fixtures/anki/.apkg-spec.yaml
+++ b/test/fixtures/anki/.apkg-spec.yaml
@@ -5,4 +5,6 @@ templates:
 
 content:
 - import_apkg:
-    note_type: Q/A Testnotetype
\ No newline at end of file
+    note_type: Q/A Testnotetype
+
+resource_paths: []
diff --git a/test/fixtures/csv/.apkg-spec.yaml b/test/fixtures/csv/.apkg-spec.yaml
index 274a5ed..b8ddf0f 100644
--- a/test/fixtures/csv/.apkg-spec.yaml
+++ b/test/fixtures/csv/.apkg-spec.yaml
@@ -15,4 +15,6 @@ content:
     - guid
     - Question
     - Answer
-    tags: []
\ No newline at end of file
+    tags: []
+
+resource_paths: []
diff --git a/test/fixtures/csv_updated_content/.apkg-spec.yaml b/test/fixtures/csv_updated_content/.apkg-spec.yaml
index c20f61a..08ebda7 100644
--- a/test/fixtures/csv_updated_content/.apkg-spec.yaml
+++ b/test/fixtures/csv_updated_content/.apkg-spec.yaml
@@ -15,4 +15,6 @@ content:
     - guid
     - Question
     - Answer
-    tags: []
\ No newline at end of file
+    tags: []
+
+resource_paths: []
diff --git a/version.txt b/version.txt
index 3eefcb9..227cea2 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.0.0
+2.0.0
-- 
GitLab