APK sources
Slack
Copy APKs posted in Slack channels, threads and forwards into a source with holtdroid-slack-sync.
Holtdroid doesn’t talk to Slack itself.
holtdroid-slack-sync is a
separate, stateless job that polls channels and writes every .apk it finds,
with a .meta.json sidecar,
into a folder or S3 prefix that the api lists as a read-only source.
It picks up APKs:
- attached to channel messages;
- in thread replies;
- inside forwarded messages.
Optionally it announces new builds the same way as the other sync jobs: one message per pass through shoutrrr (Slack, Telegram, Discord, Matrix, ntfy, email, webhooks, …). The message lists each build’s name, version, package and size, a link to the Slack message, and two launch links:
- Quick launch starts a device right away with the user’s last provider and location;
- Launch opens the launch dialog.
1. Create the Slack app
Section titled “1. Create the Slack app”The quickest way is to create it from the manifest:
- Open https://api.slack.com/apps → Create New App → From a manifest, and pick the workspace.
- Paste the manifest below, then click Create → Install to Workspace.
- Copy the Bot User OAuth Token (
xoxb-…) from OAuth & Permissions.
display_information: name: Holtdroid description: Copies APKs posted here into Holtdroid and announces them with launch links. background_color: "#8a5a3c"features: bot_user: display_name: Holtdroid always_online: falseoauth_config: scopes: bot: - channels:history - groups:history - files:read - users:read - chat:writesettings: org_deploy_enabled: false socket_mode_enabled: false token_rotation_enabled: false| Scope | Needed for |
|---|---|
channels:history, groups:history |
reading public / private channels |
files:read |
downloading the APKs |
users:read |
uploader names (optional; without it you see user IDs) |
chat:write |
announcements into Slack (optional) |
Manifests can’t set the app icon, so upload it under Basic Information
if you want one, e.g.
assets/holtdroid-icon.png.
Then invite the bot to every channel: /invite @Holtdroid. Channels are
configured by ID, e.g. C0123ABCD: open the channel details and find the ID
at the bottom of About.
2. Deploy the job
Section titled “2. Deploy the job”The chart is in the sync repository (deploy/helm/holtdroid-sync, and
oci://ghcr.io/holtdroid/charts/holtdroid-sync for tagged releases); job
picks the Slack sync:
job: slackexistingSecret: holtdroid-slack-sync # SLACK_BOT_TOKEN, S3_ACCESS_KEY, S3_SECRET_KEY, NOTIFY_URLconfig: slack: token: env:SLACK_BOT_TOKEN channels: [C0123ABCD] target: type: s3 s3: endpoint: https://s3.example.com region: us-east-1 bucket: holtdroid prefix: slack accessKey: env:S3_ACCESS_KEY secretKey: env:S3_SECRET_KEY notify: # optional: announce new builds urls: [env:NOTIFY_URL] # e.g. slack://xoxb:<bot token without xoxb->@C0123ABCD portalURL: https://holtdroid.example.com source: slackTo announce into the channel itself, reuse the bot token in the shoutrrr
URL. Builds whose message is older than notify.maxAge (24 hours by
default) aren’t announced, so the first pass over lookback stays quiet.
Every key can also come from HOLTDROID_SLACK_SYNC_* environment variables,
e.g. HOLTDROID_SLACK_SYNC_SLACK__CHANNELS=C1,C2. The full reference is in
the job’s
docs.
3. Add the source to Holtdroid
Section titled “3. Add the source to Holtdroid”Point a read-only source at the same place. Its name has to match
notify.source, or the launch links open the wrong source:
sources: - name: slack type: s3 readOnly: true s3: endpoint: https://s3.example.com region: us-east-1 bucket: holtdroid prefix: slack accessKey: env:S3_ACCESS_KEY secretKey: env:S3_SECRET_KEYWhat ends up in the source
Section titled “What ends up in the source”{channel ID}/{file ID}/{file name}.apk{channel ID}/{file ID}/{file name}.apk.meta.json| Sidecar field | Value |
|---|---|
changelog |
the message text; for a forward, the forwarder’s comment and then the original message |
note, link |
permalink of the message in the channel |
uploadedBy |
display name of whoever posted it (bots: the bot’s name; forwards: the original author) |
uploadedAt |
message time (forwards: the original message’s time) |
title |
the Slack file title, if it differs from the file name |
origin |
slack |
It also writes {file name}.apk.icon.png, the launcher icon re-rendered at
256 px, when one can be extracted.
How it polls
Section titled “How it polls”Each pass reads the history of the last lookback (7 days by default) and
lists the source. Only files the source doesn’t have yet get downloaded, so a
restart loses nothing and does no extra work. A thread is fetched again only
when it has a new reply. Edits to a top-level message rewrite its sidecar;
the APK isn’t downloaded again.
Polling has these limits:
- replies to threads whose parent is older than
lookbackare missed; - edits to thread replies that are already synced show up only after the thread gets another reply.