Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/docs/guides/obtainium.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Obtainium

Here is a config generator:

import ObtainiumConfig from '@site/src/components/obtainium.tsx';
import React from 'react';

<ObtainiumConfig />
1 change: 1 addition & 0 deletions docs/docs/partials/_mobile-app-download.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
The mobile app can be downloaded from the following places:

- [Obtainium](/docs/guides/obtainium.mdx)
- [Google Play Store](https://play.google.com/store/apps/details?id=app.alextran.immich)
- [Apple App Store](https://apps.apple.com/us/app/immich/id1613945652)
- [F-Droid](https://f-droid.org/packages/app.alextran.immich)
Expand Down
80 changes: 80 additions & 0 deletions docs/src/components/obtainium.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useState } from 'react';
export default function ObtainiumConfig(): JSX.Element {
let [inputUrl, setInputUrl] = useState('');
let [inputApiKey, setInputApiKey] = useState('');
let [archVariant, setArchVariant] = useState('');
let obtainiumUrl = `https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22app.alextran.immich%22%2C%22url%22%3A%22${inputUrl}%2Fapi%2Fserver%2Fapk-links%22%2C%22author%22%3A%22Immich%22%2C%22name%22%3A%22Immich%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%5C%22intermediateLink%5C%22%3A%5B%5D%2C%5C%22customLinkFilterRegex%5C%22%3A%5C%22%5C%22%2C%5C%22filterByLinkText%5C%22%3Afalse%2C%5C%22skipSort%5C%22%3Afalse%2C%5C%22reverseSort%5C%22%3Afalse%2C%5C%22sortByLastLinkSegment%5C%22%3Afalse%2C%5C%22versionExtractWholePage%5C%22%3Afalse%2C%5C%22requestHeader%5C%22%3A%5B%7B%5C%22requestHeader%5C%22%3A%5C%22User-Agent%3A%20Mozilla%2F5.0%20(Linux%3B%20Android%2010%3B%20K)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F114.0.0.0%20Mobile%20Safari%2F537.36%5C%22%7D%2C%7B%5C%22requestHeader%5C%22%3A%5C%22x-api-key%3A%20${inputApiKey}%5C%22%7D%5D%2C%5C%22defaultPseudoVersioningMethod%5C%22%3A%5C%22partialAPKHash%5C%22%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%2Fv(%5C%5C%5C%5Cd%2B).(%5C%5C%5C%5Cd%2B).(%5C%5C%5C%5Cd%2B)%2F%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%241.%242.%243%5C%22%2C%5C%22versionDetection%5C%22%3Atrue%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22${archVariant}%24%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22%5C%22%2C%5C%22appAuthor%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22allowInsecure%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22%5C%22%2C%5C%22refreshBeforeDownload%5C%22%3Afalse%7D%22%2C%22overrideSource%22%3Anull%7D`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apkFilterRegEx needs .apk before the $.

Could probably also use APKLinkHash for defaultPseudoVersioningMethod, since the version is in the URL.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could probably add .apk in case we ever get iOS .ipa releases but currently I'm not including it and I don't have $ at the end.

Copy link

@FibreTTP FibreTTP Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned that because it does insert a $ at the end. The %24 after ${archVariant} is a $.

edit: which makes the regex fail because there's a .apk at the end of the filenames.

Copy link
Collaborator Author

@NicholasFlamy NicholasFlamy Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, I seem to remember leaving a $ in there and having to remove it. I guess I forgot to update that and push the change. I appreciate the review!

Edit: I'll have to see if I can do that and rebase tonight.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait, I updated it in my newer PR, can you review this there?
#20589


return (
<div>
<h3>Enter values into the inputs to get a link.</h3>
<form>
<label>
URL:{' '}
<input
value={inputUrl}
placeholder="https://my.immich.app"
onChange={(update) => setInputUrl(update.target.value)}
required
/>
</label>
<br />
<label>
API Key:{' '}
<input
value={inputApiKey}
placeholder="<immich-api-key>"
onChange={(update) => setInputApiKey(update.target.value)}
required
/>
</label>
<p>
Variant:{' '}
<label>
<input
type="radio"
name="archVariantOption"
value="app-arm64-v8a-release"
onChange={(update) => setArchVariant(update.target.value)}
required
/>
arm64-v8a
</label>
<label>
<input
type="radio"
name="archVariantOption"
value="app-armeabi-v7a-release"
onChange={(update) => setArchVariant(update.target.value)}
required
/>
armeabi-v7a
</label>
<label>
<input
type="radio"
name="archVariantOption"
value="app-release"
onChange={(update) => setArchVariant(update.target.value)}
required
/>
Universal
</label>
<label>
<input
type="radio"
name="archVariantOption"
value="app-x86_64-release"
onChange={(update) => setArchVariant(update.target.value)}
required
/>
x86_64
</label>
</p>
</form>
<a hidden={!(inputUrl && inputApiKey && archVariant)} href={obtainiumUrl} target="_blank">

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium documentation

DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
<img className="h-24" alt="Get it on Obtainium" src="/img/obtainium-badge.png" />
</a>
</div>
);
}
Binary file added docs/static/img/obtainium-badge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.