[multimedia/kid3] /: CI: Create fastlane metadata for Android

Urs Fleisch <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit f2661355560c36b605aa120981f86735aa5838a8 by Urs Fleisch.
Committed on 27/07/2026 at 05:20.
Pushed by ufleisch into branch 'master'.

CI: Create fastlane metadata for Android

M  +3    -0    .kid3-cd.yml
A  +141  -0    android/fdroid2fastlane.py

https://invent.kde.org/multimedia/kid3/-/commit/f2661355560c36b605aa120981f86735aa5838a8

diff --git a/.kid3-cd.yml b/.kid3-cd.yml
index d252ded4..d1b02546 100644
--- a/.kid3-cd.yml
+++ b/.kid3-cd.yml
@@ -106,6 +106,9 @@ kid3_macos_amd64:
       ANDROID_NDK=/opt/android-sdk/ndk/23.1.7779620
       ANDROID_NDK_ROOT=/opt/android-sdk/ndk/23.1.7779620
     - !reference [.kid3_build_job, script]
+    - python3 kid3/android/fdroid2fastlane.py --fdroidyaml kid3/packaging/f-droid/net.sourceforge.kid3.yml --summary
+      'Edit audio file metadata' --icon kid3/src/app/128-apps-kid3.png --screenshot
+      https://kid3.kde.org/images/ss_android_app.png --fastlanezip $CI_PROJECT_DIR/.kde-ci-packages/fastlane-kid3.zip
     - python3 ci-notary-service/signapk.py -v --config $KDECI_SIGNAPK_CONFIG $CI_PROJECT_DIR/.kde-ci-packages/*.apk
     - python3 ci-notary-service/publishonfdroid.py -v --config $KDECI_PUBLISHONFDROID_CONFIG --fastlane $CI_PROJECT_DIR/.kde-ci-packages/fastlane-*.zip $CI_PROJECT_DIR/.kde-ci-packages/*.apk
 
diff --git a/android/fdroid2fastlane.py b/android/fdroid2fastlane.py
new file mode 100755
index 00000000..a39f494c
--- /dev/null
+++ b/android/fdroid2fastlane.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+"""
+Generate fastlane metadata from F-Droid YAML file.
+
+Usage:
+    python3 fdroid2fastlane.py --fdroidyaml kid3/packaging/f-droid/net.sourceforge.kid3.yml \
+        --summary 'Edit audio file metadata' \
+        --icon kid3/src/app/128-apps-kid3.png \
+        --screenshot https://kid3.kde.org/images/ss_android_app.png \
+        --fastlanezip fastlane.zip
+"""
+
+import argparse
+import shutil
+import urllib.request
+import zipfile
+from pathlib import Path
+from tempfile import TemporaryDirectory
+
+import yaml
+
+
+def parse_description(description_text: str | list[str] | None) -> str:
+    """
+    Parse the description from F-Droid YAML.
+    Handles both plain text and the |- formatted multi-line strings.
+    """
+    if description_text is None:
+        return ""
+    if isinstance(description_text, str):
+        return description_text.strip()
+    if isinstance(description_text, list):
+        return "\n".join(description_text).strip()
+    return str(description_text).strip()
+
+
+def extract_metadata(fdroid_yaml_path: str) -> dict[str, str]:
+    """
+    Extract relevant metadata from F-Droid YAML file.
+    Returns a dictionary with title, short_description, full_description.
+    """
+    with open(fdroid_yaml_path, "r", encoding="utf-8") as f:
+        data = yaml.safe_load(f)
+    description = parse_description(data.get("Description", ""))
+    short = ""
+    if description:
+        lines = [line.strip() for line in description.split("\n") if line.strip()]
+        if lines:
+            short = lines[0]
+    else:
+        description = data.get("Summary", "")
+        short = description
+    if len(short) > 80:
+        short = short[:77] + "..."
+    return {
+        "title": data.get("AutoName", ""),
+        "short_description": short,
+        "full_description": description,
+    }
+
+
+def create_fastlane_structure(
+    metadata: dict[str, str], summary="", icon_path="", screenshot_path=""
+) -> TemporaryDirectory[str]:
+    """
+    Create the fastlane directory structure in a temporary directory.
+    Returns the path to the temp directory.
+    """
+    temp_dir = TemporaryDirectory()
+    root_path = Path(temp_dir.name)
+    metadata_dir = root_path / "metadata" / "android" / "en-US"
+    metadata_dir.mkdir(parents=True, exist_ok=True)
+    title_file = metadata_dir / "title.txt"
+    title_file.write_text(metadata["title"], encoding="utf-8")
+    short_desc_file = metadata_dir / "short_description.txt"
+    short_desc_file.write_text(
+        summary if summary else metadata["short_description"], encoding="utf-8"
+    )
+    full_desc_file = metadata_dir / "full_description.txt"
+    full_desc_file.write_text(metadata["full_description"], encoding="utf-8")
+    images_dir = root_path / "metadata" / "android" / "images"
+    images_dir.mkdir(parents=True, exist_ok=True)
+    if icon_path and Path(icon_path).exists():
+        shutil.copy2(icon_path, images_dir / "icon.png")
+    if screenshot_path:
+        screenshots_dir = images_dir / "phoneScreenshots"
+        screenshots_dir.mkdir(parents=True, exist_ok=True)
+        if screenshot_path.startswith("http"):
+            try:
+                urllib.request.urlretrieve(
+                    screenshot_path, screenshots_dir / "shot.png"
+                )
+            except urllib.request.HTTPError:
+                print(f"Could not download {screenshot_path}")
+        if Path(screenshot_path).exists():
+            shutil.copy2(screenshot_path, screenshots_dir)
+    return temp_dir
+
+
+def create_fastlane_zip(
+    temp_dir: TemporaryDirectory[str], output_zip_path: str
+) -> None:
+    """
+    Create a zip file from the temporary directory structure.
+    """
+    with zipfile.ZipFile(output_zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
+        root_path = Path(temp_dir.name)
+        for file_path in root_path.rglob("*"):
+            if file_path.is_file():
+                rel_path = file_path.relative_to(root_path)
+                zipf.write(file_path, str(rel_path))
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description="Generate fastlane metadata from F-Droid YAML file"
+    )
+    parser.add_argument("--fdroidyaml", required=True, help="Path to F-Droid YAML file")
+    parser.add_argument("--summary", help="Short description", default="")
+    parser.add_argument("--icon", help="Paths to icon file", default="")
+    parser.add_argument("--screenshot", help="Path to screenshot file", default="")
+    parser.add_argument(
+        "--fastlanezip",
+        required=True,
+        help="Path where the output fastlane zip file should be created",
+    )
+    args = parser.parse_args()
+    metadata = extract_metadata(args.fdroidyaml)
+    temp_dir = create_fastlane_structure(
+        metadata,
+        summary=args.summary,
+        icon_path=args.icon,
+        screenshot_path=args.screenshot,
+    )
+    create_fastlane_zip(temp_dir, args.fastlanezip)
+    temp_dir.cleanup()
+    print(f"Created fastlane zip archive: {args.fastlanezip}")
+
+
+if __name__ == "__main__":
+    main()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.