aboutsummaryrefslogtreecommitdiff
path: root/src/bots/fdroid/index.rs
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2026-10-25 09:08:01 +0100
committerMartin Fischer <martin@push-f.com>2026-10-25 19:10:47 +0100
commit41212a7a15198e53d205252a02069a7dd6ddadeb (patch)
tree38a24eebf956b2453675ac1cefec925faf09de02 /src/bots/fdroid/index.rs
initial commit
Diffstat (limited to 'src/bots/fdroid/index.rs')
-rw-r--r--src/bots/fdroid/index.rs97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/bots/fdroid/index.rs b/src/bots/fdroid/index.rs
new file mode 100644
index 0000000..61cc44d
--- /dev/null
+++ b/src/bots/fdroid/index.rs
@@ -0,0 +1,97 @@
+//! Types for the F-Droid repository index.
+
+use std::collections::HashMap;
+
+use serde::{Deserialize, Deserializer};
+
+pub(super) const PHONE_DEVICE_TYPE: &str = "phone";
+pub(super) const EN_LOCALE: &str = "en-US";
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Index {
+ pub(super) repo: Repo,
+ pub(super) packages: HashMap<String, Package>,
+}
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Repo {
+ pub(super) timestamp: u64,
+}
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Package {
+ pub(super) metadata: Metadata,
+ /// Releases keyed by the APK's SHA-256 digest.
+ pub(super) versions: HashMap<String, Version>,
+}
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Version {
+ /// Anti-feature explanations keyed first by anti-feature name and then by locale.
+ #[serde(default, rename = "antiFeatures")]
+ pub(super) anti_features: HashMap<AntiFeature, HashMap<String, String>>,
+}
+
+/// An [anti-feature](https://f-droid.org/docs/Anti-Features/).
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub(super) enum AntiFeature {
+ Ads,
+ DisabledAlgorithm,
+ KnownVuln,
+ NoSourceSince,
+ NonFreeAdd,
+ NonFreeAssets,
+ NonFreeDep,
+ NonFreeNet,
+ TetheredNet,
+ Tracking,
+ Other(String),
+}
+
+impl<'de> Deserialize<'de> for AntiFeature {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let name = String::deserialize(deserializer)?;
+ Ok(match name.as_str() {
+ "Ads" => Self::Ads,
+ "DisabledAlgorithm" => Self::DisabledAlgorithm,
+ "KnownVuln" => Self::KnownVuln,
+ "NoSourceSince" => Self::NoSourceSince,
+ "NonFreeAdd" => Self::NonFreeAdd,
+ "NonFreeAssets" => Self::NonFreeAssets,
+ "NonFreeDep" => Self::NonFreeDep,
+ "NonFreeNet" => Self::NonFreeNet,
+ "TetheredNet" => Self::TetheredNet,
+ "Tracking" => Self::Tracking,
+ _ => {
+ tracing::warn!("observed unknown F-Droid anti-feature {name}");
+ Self::Other(name)
+ }
+ })
+ }
+}
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Metadata {
+ pub(super) added: u64,
+ /// App names keyed by locale. Every package has an `en-US` name.
+ #[serde(default)]
+ pub(super) name: HashMap<String, String>,
+ /// Short app descriptions keyed by locale.
+ #[serde(default)]
+ pub(super) summary: HashMap<String, String>,
+ /// Screenshots keyed first by device type and then by locale.
+ #[serde(default)]
+ pub(super) screenshots: HashMap<String, HashMap<String, Vec<Screenshot>>>,
+}
+
+#[derive(Debug, Deserialize)]
+pub(super) struct Screenshot {
+ /// Path to the screenshot relative to the repository address.
+ pub(super) name: String,
+ /// Screenshot file size in bytes, retained for enforcing upload limits.
+ #[allow(dead_code)]
+ pub(super) size: u64,
+}