Compare commits

...

56 Commits

Author SHA1 Message Date
Imran
59cc08f28a Merge pull request #1439 from ImranR98/dev
- Allow any source to be overridden (#1420)
- Bugfix for installing apps with ID change step (#1424)
- Bugfix: 'null' changelog for some track-only apps (#1425)
- Show latest APK name/count on app page (#1426)
- More BG update interval options (#1431)
2024-03-01 20:37:02 -05:00
Imran Remtulla
afc0c3a2fa Upgrade packages, increment version 2024-03-01 20:34:15 -05:00
Imran Remtulla
a827046acc More BG update interval options (#1431) 2024-03-01 20:21:46 -05:00
Imran Remtulla
fd8f967036 Show latest APK name/count on app page (#1426) 2024-03-01 20:18:07 -05:00
Imran Remtulla
26be524c6d Bugfix: 'null' changelog for some track-only apps (#1425) 2024-03-01 19:50:04 -05:00
Imran Remtulla
8ec3360575 Merge remote-tracking branch 'origin/main' into dev 2024-03-01 19:46:38 -05:00
Imran Remtulla
f66753498b Bugfix for installing apps with ID change step (#1424) 2024-03-01 19:46:30 -05:00
Imran
90e6e5a3a3 Update README.md 2024-02-29 19:17:53 -05:00
Imran
2c4713ff25 Merge pull request #1411 from akramer-zibra/fix-gitlab-request-headers
Solve issues with gitlab .apk files and cloudflare protection
2024-02-26 10:56:11 -05:00
Achim
ef3b01ac56 Use gitlab host defined in class member variable 2024-02-26 13:42:56 +01:00
Imran Remtulla
1cfb258dcc Allow any source to be overridden (#1420) 2024-02-25 15:41:12 -05:00
Imran
d13464a392 Merge pull request #1415 from ngocanhtve/main
Update vi.json
2024-02-25 14:20:38 -05:00
Imran
f1dd50faee Merge pull request #1413 from DwainZwerg/patch-13
Update README.md
2024-02-25 14:20:27 -05:00
ngocanhtve
6f5315db27 Update vi.json 2024-02-20 21:00:39 +07:00
ngocanhtve
02922c3c8e Merge remote-tracking branch 'upstream/main' 2024-02-20 20:35:07 +07:00
DwainZwerg
03ef649c0f Update README.md
Add IzzyOnDroid-Badge, since it isn't out of day
2024-02-20 09:38:57 +00:00
Achim
9083e28637 Merge branch 'main' into fix-gitlab-request-headers 2024-02-19 16:16:42 +01:00
Achim
cfa4c680cf Set referer header for gitlab app source context
There occur issues if a gitlab project refers in its release data to external hosted .apk file. In some cases (e.g. Aurora Store) download is not possible because cloudflare protection gives "forbidden" error. The referer header seems to pacify this cloudflare protection. Tested with Android 14 in an AVD emulator.

Related to: #1397, #1389, #1384, #1382, #1381, #1380, #1359, #854, #785, #697
2024-02-19 16:02:49 +01:00
Imran
a5b3b9d1d0 Merge pull request #1408 from ImranR98/dev
- Improved URL handling for F-Droid third party repos (#1399)
- Fixed F-Droid repo search (#1400) + general search bugfixes
- Improved APK filter for F-Droid (#1386)
- Don't remove storage permission (#1391)
- Jump in versionCode to fix updates in x86 versions (#1370)
2024-02-18 18:20:54 -05:00
Imran Remtulla
13cd7e76c1 Update Flutter + packages, increment version 2024-02-18 18:19:29 -05:00
Imran Remtulla
6e7ccfba37 Merge remote-tracking branch 'origin/main' into dev 2024-02-18 18:18:40 -05:00
Imran Remtulla
34fd673e25 Jump in versionCode to fix updates in x86 versions (#1370) 2024-02-18 18:16:33 -05:00
Imran Remtulla
db484f7b28 Don't remove storage permission (#1391) 2024-02-18 18:13:17 -05:00
Imran Remtulla
b4cf0f5d29 Improved APK filter for F-Droid (#1386) 2024-02-18 18:00:03 -05:00
Imran Remtulla
4db205dd9a Fixed F-Droid repo search (#1400) + general search bugfixes 2024-02-18 17:43:24 -05:00
Imran Remtulla
64f8e2a57b Improved URL handling for F-Droid third party repos (#1399) 2024-02-18 17:00:56 -05:00
Imran
eddc245ff4 Update issue templates 2024-02-15 17:13:02 -05:00
Imran
ed2f0f2c0c Merge pull request #1368 from gidano/main
Update hu.json
2024-02-03 15:47:45 -05:00
Imran
7d5a422855 Merge pull request #1371 from inson1/patch-1
Add F-droid badge to README.md
2024-02-03 15:47:28 -05:00
inson1
e420862546 Add F-droid badge to README.md 2024-02-03 17:45:32 +01:00
gidano
2cc59948a7 Update hu.json 2024-02-03 10:59:10 +01:00
Imran
188d33199e Merge pull request #1365 from heuwerk/patch-1
Update de.json
2024-02-03 04:29:36 -05:00
Imran
24928261bb Merge pull request #1367 from ImranR98/dev
Updated a package
2024-02-03 04:29:26 -05:00
Imran Remtulla
4c7bda8343 Updated a package 2024-02-03 04:24:59 -05:00
heuwerk
d88709c999 Update de.json
Added forgotten translation
2024-02-02 11:30:20 +01:00
heuwerk
29e1481a3b Update de.json
Changed "Update" in translated text to "Aktualisierung", since it is used everywhere else.
2024-02-02 11:24:47 +01:00
Imran
9d76359543 Merge pull request #1364 from ImranR98/dev
Add DeepL translations as placeholders
2024-02-01 20:34:46 -05:00
Imran Remtulla
f50e791221 Add DeepL translations as placeholders 2024-02-01 20:34:32 -05:00
Imran
7d08e5225c Merge pull request #1363 from ImranR98/dev
Correctly report and auto-delete bad APKs (#1251)
2024-02-01 19:32:15 -05:00
Imran Remtulla
3842c1e2df Update packages, increment version 2024-02-01 19:31:32 -05:00
Imran Remtulla
21b1990991 Merge remote-tracking branch 'origin/main' into dev 2024-02-01 19:31:19 -05:00
Imran Remtulla
e278c9fb5a Correctly report and auto-delete bad APKs (#1251) 2024-02-01 19:26:36 -05:00
Imran
bfa29bb7c2 Merge pull request #1361 from DwainZwerg/patch-12
Translation of the Note of the sources window
2024-02-01 19:00:41 -05:00
DwainZwerg
efa55a9696 Update de.json
Okay → OK because it’s shorter and more common
2024-01-31 14:55:23 +00:00
DwainZwerg
8888cd6264 Update de.json
Translation of the note of the Sources Menu
2024-01-31 14:51:08 +00:00
Imran
34e2c014e3 Merge pull request #1357 from jont4/main
Update pt translation
2024-01-29 18:44:36 -05:00
jont4
5d92a6d013 Update pt translation 2024-01-28 22:58:17 -03:00
Imran
fb03b2e95c Merge pull request #1356 from ImranR98/dev
Better support for SourceForge (#1352), Remove READ_EXTERNAL_STORAGE again (#1309) + fix typo
2024-01-28 17:00:10 -05:00
Imran
5a1e09564c Merge pull request #1350 from gidano/main
Update hu.json
2024-01-28 16:58:53 -05:00
Imran
3783eba401 Merge pull request #1351 from unbranched/patch-5
Update it.json
2024-01-28 16:58:39 -05:00
Imran Remtulla
a3530ce6bb Remove READ_EXTERNAL_STORAGE again (#1309) + fix typo 2024-01-28 16:58:09 -05:00
Imran Remtulla
27d8655d58 Better support for SourceForge (#1352) 2024-01-28 16:32:58 -05:00
unbranched
fb845ce601 Update it.json 2024-01-28 10:59:15 +00:00
gidano
dbd433df9d Update hu.json 2024-01-28 09:15:28 +01:00
ngocanhtve
8dd8f471a2 Update vi.json 2023-11-20 10:09:45 +07:00
ngocanhtve
657d1cd042 Update vi.json 2023-11-20 10:00:08 +07:00
40 changed files with 590 additions and 278 deletions

View File

@@ -10,6 +10,7 @@ assignees: ''
**Prerequisites** **Prerequisites**
<!-- Please ensure your request is not part of an existing issue. --> <!-- Please ensure your request is not part of an existing issue. -->
<!-- Please ensure you have checked the Obtainium Wiki. --> <!-- Please ensure you have checked the Obtainium Wiki. -->
<!-- Please ensure your request is an actual bug and not intended behaviour (this is frequently the case for issues involving version strings and the HTML source. -->
**Describe the bug** **Describe the bug**
<!-- A clear and concise description of what the bug is. --> <!-- A clear and concise description of what the bug is. -->

View File

@@ -14,11 +14,14 @@ assignees: ''
**Describe the feature** **Describe the feature**
<!-- A clear and concise description of what you want to happen. <!-- A clear and concise description of what you want to happen.
For new Sources, it's preferable (not required) if you suggest how the following details can be extracted from the Source in a reliable way (like an API or through web scraping): For new Sources, please ensure:
1. It is not already possible to use the HTML Source for your purposes.
2. It must be possible to extract the following details from the Source in a reliable way:
- The App version (or any release-specific identifier - a "pseudo-version") for the latest release - The App version (or any release-specific identifier - a "pseudo-version") for the latest release
- One or more APK URL(s) for the latest release - One or more APK URL(s) for the latest release
- Above details for previous releases (optional) - Above details for previous releases (optional)
If you're not sure about 1 or 2, open a discussion item instead.
Note that the Web scraper cannot deal with JavaScript-enabled content. --> Note that the Web scraper cannot deal with JavaScript-enabled content. -->
**Describe alternatives you've considered (if applicable)** **Describe alternatives you've considered (if applicable)**

View File

@@ -42,7 +42,13 @@ Currently supported App sources:
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png" [<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
alt="Get it on GitHub" alt="Get it on GitHub"
height="80">](https://github.com/ImranR98/Obtainium/releases) height="80">](https://github.com/ImranR98/Obtainium/releases)
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
alt="Get it on IzzyOnDroid"
height="80">](https://apt.izzysoft.de/fdroid/index/apk/dev.imranr.obtainium)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/dev.imranr.obtainium.fdroid/)
[PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index) [PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index)
## Limitations ## Limitations

View File

@@ -70,6 +70,6 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" /> android:maxSdkVersion="29" />\
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
</manifest> </manifest>

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Uklonite zastarjeli filter aplikacija", "removeOutdatedFilter": "Uklonite zastarjeli filter aplikacija",
"showOutdatedOnly": "Prikaži samo zastarjele aplikacije", "showOutdatedOnly": "Prikaži samo zastarjele aplikacije",
"filter": "Filtriranje", "filter": "Filtriranje",
"filterActive": "Filtriranje",
"filterApps": "Filtriraj aplikacije", "filterApps": "Filtriraj aplikacije",
"appName": "Naziv aplikacije", "appName": "Naziv aplikacije",
"author": "Autor", "author": "Autor",
@@ -300,6 +299,7 @@
"invertRegEx": "Obrni regularni izraz", "invertRegEx": "Obrni regularni izraz",
"note": "Note", "note": "Note",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
"badDownload": "The APK could not be parsed (incompatible or partial download)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} i još jedna aplikacija je vjerovatno ažurirana.", "one": "{} i još jedna aplikacija je vjerovatno ažurirana.",
"other": "{} i još {} aplikacija su vjerovatno ažurirane." "other": "{} i još {} aplikacija su vjerovatno ažurirane."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Odstranit filtr Neaktuální", "removeOutdatedFilter": "Odstranit filtr Neaktuální",
"showOutdatedOnly": "Zobrazovat pouze zastaralé aplikace", "showOutdatedOnly": "Zobrazovat pouze zastaralé aplikace",
"filter": "Filtr", "filter": "Filtr",
"filterActive": "Filtr *",
"filterApps": "Filtrovat aplikace", "filterApps": "Filtrovat aplikace",
"appName": "Název aplikace", "appName": "Název aplikace",
"author": "Autor", "author": "Autor",
@@ -292,14 +291,15 @@
"useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání", "useLatestAssetDateAsReleaseDate": "Použít poslední nahrané dílo jako datum vydání",
"defaultPseudoVersioningMethod": "Výchozí metoda pseudoverze", "defaultPseudoVersioningMethod": "Výchozí metoda pseudoverze",
"partialAPKHash": "Částečný hash APK", "partialAPKHash": "Částečný hash APK",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "Odkaz APK Hash",
"directAPKLink": "Přímý odkaz APK", "directAPKLink": "Přímý odkaz APK",
"pseudoVersionInUse": "Pseudoverze se používá", "pseudoVersionInUse": "Pseudoverze se používá",
"installed": "Instalováno", "installed": "Instalováno",
"latest": "Nejnovější", "latest": "Nejnovější",
"invertRegEx": "Invertovat regulární výraz", "invertRegEx": "Invertovat regulární výraz",
"note": "Note", "note": "Poznámka",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Rozbalovací seznam \"{}\" lze použít k dosažení vlastních/obvyklých instancí libovolného zdroje.",
"badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit Apku?", "one": "Odstranit Apku?",
"other": "Odstranit Apky?" "other": "Odstranit Apky?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} a 1 další aplikace možno aktualizovat", "one": "{} a 1 další aplikace možno aktualizovat",
"other": "{} a {} další aplikace mohou být aktualizovány." "other": "{} a {} další aplikace mohou být aktualizovány."
},
"apk": {
"one": "{} APK",
"other": "{} APK"
} }
} }

View File

@@ -9,7 +9,7 @@
"placeholder": "Platzhalter", "placeholder": "Platzhalter",
"someErrors": "Es traten einige Fehler auf", "someErrors": "Es traten einige Fehler auf",
"unexpectedError": "Unerwarteter Fehler", "unexpectedError": "Unerwarteter Fehler",
"ok": "Okay", "ok": "OK",
"and": "und", "and": "und",
"githubPATLabel": "GitHub Personal Access Token (Erhöht das Ratenlimit)", "githubPATLabel": "GitHub Personal Access Token (Erhöht das Ratenlimit)",
"includePrereleases": "Vorabversionen einbeziehen", "includePrereleases": "Vorabversionen einbeziehen",
@@ -30,7 +30,7 @@
"app": "App", "app": "App",
"appsFromSourceAreTrackOnly": "Apps aus dieser Quelle sind nur zum Nachverfolgen.", "appsFromSourceAreTrackOnly": "Apps aus dieser Quelle sind nur zum Nachverfolgen.",
"youPickedTrackOnly": "Sie haben die Option „Nur Nachverfolgen“ gewählt.", "youPickedTrackOnly": "Sie haben die Option „Nur Nachverfolgen“ gewählt.",
"trackOnlyAppDescription": "Die App wird auf Updates überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.", "trackOnlyAppDescription": "Die App wird auf Aktualisierungen überwacht, aber Obtainium wird sie nicht herunterladen oder installieren.",
"cancelled": "Abgebrochen", "cancelled": "Abgebrochen",
"appAlreadyAdded": "App bereits hinzugefügt", "appAlreadyAdded": "App bereits hinzugefügt",
"alreadyUpToDateQuestion": "App bereits auf dem neuesten Stand?", "alreadyUpToDateQuestion": "App bereits auf dem neuesten Stand?",
@@ -80,7 +80,6 @@
"removeOutdatedFilter": "App-Filter Nicht aktuell entfernen", "removeOutdatedFilter": "App-Filter Nicht aktuell entfernen",
"showOutdatedOnly": "Nur nicht aktuelle Apps anzeigen", "showOutdatedOnly": "Nur nicht aktuelle Apps anzeigen",
"filter": "Filter", "filter": "Filter",
"filterActive": "Filter *",
"filterApps": "Apps filtern", "filterApps": "Apps filtern",
"appName": "App Name", "appName": "App Name",
"author": "Autor", "author": "Autor",
@@ -226,7 +225,7 @@
"tryInferAppIdFromCode": "Versuche, die App-ID aus dem Quellcode zu ermitteln", "tryInferAppIdFromCode": "Versuche, die App-ID aus dem Quellcode zu ermitteln",
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps", "removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
"pickHighestVersionCode": "Automatische Auswahl des APK mit höchstem Versionscode", "pickHighestVersionCode": "Automatische Auswahl des APK mit höchstem Versionscode",
"checkUpdateOnDetailPage": "Nach Updates suchen, wenn eine App-Detailseite geöffnet wird", "checkUpdateOnDetailPage": "Nach Aktualisierungen suchen, wenn eine App-Detailseite geöffnet wird",
"disablePageTransitions": "Animationen für Seitenübergänge deaktivieren", "disablePageTransitions": "Animationen für Seitenübergänge deaktivieren",
"reversePageTransitions": "Umgekehrte Animationen für Seitenübergänge", "reversePageTransitions": "Umgekehrte Animationen für Seitenübergänge",
"minStarCount": "Minimale Anzahl von Sternen", "minStarCount": "Minimale Anzahl von Sternen",
@@ -238,7 +237,7 @@
"filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck filtern", "filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck filtern",
"customLinkFilterRegex": "Benutzerdefinierter APK Link Filter nach Regulärem Ausdruck (Standard '.apk$')", "customLinkFilterRegex": "Benutzerdefinierter APK Link Filter nach Regulärem Ausdruck (Standard '.apk$')",
"appsPossiblyUpdated": "App Aktualisierungen wurden versucht", "appsPossiblyUpdated": "App Aktualisierungen wurden versucht",
"appsPossiblyUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Updates für eine oder mehrere Apps möglicherweise im Hintergrund durchgeführt wurden", "appsPossiblyUpdatedNotifDescription": "Benachrichtigt den Benutzer, dass Aktualisierungen für eine oder mehrere Apps möglicherweise im Hintergrund durchgeführt wurden",
"xWasPossiblyUpdatedToY": "{} wurde möglicherweise aktualisiert auf {}.", "xWasPossiblyUpdatedToY": "{} wurde möglicherweise aktualisiert auf {}.",
"enableBackgroundUpdates": "Aktiviere Hintergrundaktualisierungen", "enableBackgroundUpdates": "Aktiviere Hintergrundaktualisierungen",
"backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist möglicherweise nicht für alle Apps möglich.", "backgroundUpdateReqsExplanation": "Die Hintergrundaktualisierung ist möglicherweise nicht für alle Apps möglich.",
@@ -268,7 +267,7 @@
"runBgCheckNow": "Hintergrundaktualisierungsprüfung jetzt durchführen", "runBgCheckNow": "Hintergrundaktualisierungsprüfung jetzt durchführen",
"versionExtractWholePage": "Versions-Extraktion per RegEx auf die gesamte Seite anwenden", "versionExtractWholePage": "Versions-Extraktion per RegEx auf die gesamte Seite anwenden",
"installing": "Installiere", "installing": "Installiere",
"skipUpdateNotifications": "Keine Benachrichtigung zu App-Updates geben", "skipUpdateNotifications": "Keine Benachrichtigung zu App-Aktualisierungen geben",
"updatesAvailableNotifChannel": "Aktualisierungen verfügbar", "updatesAvailableNotifChannel": "Aktualisierungen verfügbar",
"appsUpdatedNotifChannel": "Apps aktualisiert", "appsUpdatedNotifChannel": "Apps aktualisiert",
"appsPossiblyUpdatedNotifChannel": "App Aktualisierungen wurden versucht", "appsPossiblyUpdatedNotifChannel": "App Aktualisierungen wurden versucht",
@@ -294,12 +293,13 @@
"partialAPKHash": "partieller APK-Hash", "partialAPKHash": "partieller APK-Hash",
"APKLinkHash": "APK-Link-Hash", "APKLinkHash": "APK-Link-Hash",
"directAPKLink": "Direkter APK-Link", "directAPKLink": "Direkter APK-Link",
"pseudoVersionInUse": "Pseudoversionen sind in Benutzung", "pseudoVersionInUse": "Es werden Pseudoversionen verwendet",
"installed": "Installiert", "installed": "Installiert",
"latest": "Neueste Version", "latest": "Neueste Version",
"invertRegEx": "Regulären Ausdruck invertieren", "invertRegEx": "Regulären Ausdruck invertieren",
"note": "Note", "note": "Hinweis",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Das „{}“-Dropdown-Menü kann verwendet werden, um selbst gehostete/angepasste Instanzen einer beliebigen Quelle zu erreichen.",
"badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} und 1 weitere Anwendung wurden möglicherweise aktualisiert.", "one": "{} und 1 weitere Anwendung wurden möglicherweise aktualisiert.",
"other": "{} und {} weitere Anwendungen wurden möglicherweise aktualisiert." "other": "{} und {} weitere Anwendungen wurden möglicherweise aktualisiert."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Remove Out-of-Date App Filter", "removeOutdatedFilter": "Remove Out-of-Date App Filter",
"showOutdatedOnly": "Show Out-of-Date Apps Only", "showOutdatedOnly": "Show Out-of-Date Apps Only",
"filter": "Filter", "filter": "Filter",
"filterActive": "Filter *",
"filterApps": "Filter Apps", "filterApps": "Filter Apps",
"appName": "App Name", "appName": "App Name",
"author": "Author", "author": "Author",
@@ -300,6 +299,7 @@
"invertRegEx": "Invert regular expression", "invertRegEx": "Invert regular expression",
"note": "Note", "note": "Note",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
"badDownload": "The APK could not be parsed (incompatible or partial download)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} and 1 more app may have been updated.", "one": "{} and 1 more app may have been updated.",
"other": "{} and {} more apps may have been updated." "other": "{} and {} more apps may have been updated."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Elimiar filtro de aplicaciones desactualizado", "removeOutdatedFilter": "Elimiar filtro de aplicaciones desactualizado",
"showOutdatedOnly": "Mostrar solo aplicaciones desactualizadas", "showOutdatedOnly": "Mostrar solo aplicaciones desactualizadas",
"filter": "Filtrar", "filter": "Filtrar",
"filterActive": "Filtrar *",
"filterApps": "Filtrar Actualizaciones", "filterApps": "Filtrar Actualizaciones",
"appName": "Nombre de la aplicación", "appName": "Nombre de la aplicación",
"author": "Autor", "author": "Autor",
@@ -298,8 +297,9 @@
"installed": "Instalado", "installed": "Instalado",
"latest": "Versión más reciente", "latest": "Versión más reciente",
"invertRegEx": "Invertir expresión regular", "invertRegEx": "Invertir expresión regular",
"note": "Note", "note": "Nota",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "El desplegable \"{}\" puede utilizarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
"badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar Aplicación?", "one": "¿Eliminar Aplicación?",
"other": "¿Eliminar Aplicaciones?" "other": "¿Eliminar Aplicaciones?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} y 1 aplicación más podría haber sido actualizada.", "one": "{} y 1 aplicación más podría haber sido actualizada.",
"other": "{} y {} aplicaciones más podrían haber sido actualizadas." "other": "{} y {} aplicaciones más podrían haber sido actualizadas."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "فیلتر برنامه قدیمی را حذف کنید", "removeOutdatedFilter": "فیلتر برنامه قدیمی را حذف کنید",
"showOutdatedOnly": "فقط برنامه های قدیمی را نشان دهید", "showOutdatedOnly": "فقط برنامه های قدیمی را نشان دهید",
"filter": "فیلتر", "filter": "فیلتر",
"filterActive": "فیلتر *",
"filterApps": "فیلتر کردن برنامه ها", "filterApps": "فیلتر کردن برنامه ها",
"appName": "نام برنامه", "appName": "نام برنامه",
"author": "سازنده", "author": "سازنده",
@@ -300,6 +299,7 @@
"invertRegEx": "معکوس کردن عبارت منظم", "invertRegEx": "معکوس کردن عبارت منظم",
"note": "Note", "note": "Note",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
"badDownload": "The APK could not be parsed (incompatible or partial download)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.", "one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",
"other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند." "other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Supprimer le filtre d'application obsolète", "removeOutdatedFilter": "Supprimer le filtre d'application obsolète",
"showOutdatedOnly": "Afficher uniquement les applications obsolètes", "showOutdatedOnly": "Afficher uniquement les applications obsolètes",
"filter": "Filtre", "filter": "Filtre",
"filterActive": "Filtre *",
"filterApps": "Filtrer les applications", "filterApps": "Filtrer les applications",
"appName": "Nom de l'application", "appName": "Nom de l'application",
"author": "Auteur", "author": "Auteur",
@@ -299,7 +298,8 @@
"latest": "Dernier", "latest": "Dernier",
"invertRegEx": "Inverser l'expression régulière", "invertRegEx": "Inverser l'expression régulière",
"note": "Note", "note": "Note",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "La liste déroulante \"{}\" peut être utilisée pour accéder aux instances auto-hébergées/personnalisées de n'importe quelle source.",
"badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application ?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications ?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"une": "{} et 1 application supplémentaire ont peut-être été mises à jour.", "une": "{} et 1 application supplémentaire ont peut-être été mises à jour.",
"other": "{} et {} autres applications peuvent avoir été mises à jour." "other": "{} et {} autres applications peuvent avoir été mises à jour."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Távolítsa el az elavult app szűrőt", "removeOutdatedFilter": "Távolítsa el az elavult app szűrőt",
"showOutdatedOnly": "Csak az elavult appok megjelenítése", "showOutdatedOnly": "Csak az elavult appok megjelenítése",
"filter": "Szűrő", "filter": "Szűrő",
"filterActive": "Szűrő *",
"filterApps": "Appok szűrése", "filterApps": "Appok szűrése",
"appName": "App név", "appName": "App név",
"author": "Szerző", "author": "Szerző",
@@ -287,7 +286,7 @@
"shizukuBinderNotFound": "A Shizuku nem fut", "shizukuBinderNotFound": "A Shizuku nem fut",
"useSystemFont": "Használja a rendszer betűtípusát", "useSystemFont": "Használja a rendszer betűtípusát",
"systemFontError": "Hiba a rendszer betűtípusának betöltésekor: {}", "systemFontError": "Hiba a rendszer betűtípusának betöltésekor: {}",
"useVersionCodeAsOSVersion": "Az app versionCode használata a rendszer által észlelt verzióként", "useVersionCodeAsOSVersion": "Az app verziókód használata a rendszer által észlelt verzióként",
"requestHeader": "Kérelem fejléc", "requestHeader": "Kérelem fejléc",
"useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként", "useLatestAssetDateAsReleaseDate": "Használja a legújabb tartalomfeltöltést megjelenési dátumként",
"defaultPseudoVersioningMethod": "Alapértelmezett álversziós módszer", "defaultPseudoVersioningMethod": "Alapértelmezett álversziós módszer",
@@ -298,11 +297,12 @@
"installed": "Telepített", "installed": "Telepített",
"latest": "Legújabb", "latest": "Legújabb",
"invertRegEx": "Invertált reguláris kifejezés", "invertRegEx": "Invertált reguláris kifejezés",
"note": "Note", "note": "Megjegyzés:",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "A \"{}\" legördülő menü használható bármely forrás saját üzemeltetésű/egyéni példányainak eléréséhez.",
"badDownload": "Az APK-t nem lehetett elemezni (inkompatibilis vagy részleges letöltés)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazást?" "other": "Eltávolítja az alkalmazásokat?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "Túl sok kérés (korlátozott arány) próbálja újra {} perc múlva", "one": "Túl sok kérés (korlátozott arány) próbálja újra {} perc múlva",
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} és 1 további alkalmazás is frissült.", "one": "{} és 1 további alkalmazás is frissült.",
"other": "{} és {} további alkalmazás is frissült." "other": "{} és {} további alkalmazás is frissült."
},
"apk": {
"one": "{} APK",
"other": "{} APK-k"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Rimuovi il filtro per le app non aggiornate", "removeOutdatedFilter": "Rimuovi il filtro per le app non aggiornate",
"showOutdatedOnly": "Mostra solo le app non aggiornate", "showOutdatedOnly": "Mostra solo le app non aggiornate",
"filter": "Filtri", "filter": "Filtri",
"filterActive": "Filtri *",
"filterApps": "Filtra app", "filterApps": "Filtra app",
"appName": "Nome dell'app", "appName": "Nome dell'app",
"author": "Autore", "author": "Autore",
@@ -111,7 +110,7 @@
"dark": "Scuro", "dark": "Scuro",
"light": "Chiaro", "light": "Chiaro",
"followSystem": "Segui il sistema", "followSystem": "Segui il sistema",
"useBlackTheme": "Usa il tema Nero puro", "useBlackTheme": "Usa il tema nero puro",
"appSortBy": "App ordinate per", "appSortBy": "App ordinate per",
"authorName": "Autore/Nome", "authorName": "Autore/Nome",
"nameAuthor": "Nome/Autore", "nameAuthor": "Nome/Autore",
@@ -283,13 +282,13 @@
"parallelDownloads": "Permetti download paralleli", "parallelDownloads": "Permetti download paralleli",
"installMethod": "Metodo d'installazione", "installMethod": "Metodo d'installazione",
"normal": "Normale", "normal": "Normale",
"root": "Radice", "root": "Root",
"shizukuBinderNotFound": "Shizuku non è in esecuzione", "shizukuBinderNotFound": "Shizuku non è in esecuzione",
"useSystemFont": "Utilizza il carattere di sistema", "useSystemFont": "Usa i caratteri di sistema",
"systemFontError": "Errore durante il caricamento del carattere di sistema: {}", "systemFontError": "Errore durante il caricamento dei caratteri di sistema: {}",
"useVersionCodeAsOSVersion": "Utilizza il codice versione dell'app come versione rilevata dal sistema operativo", "useVersionCodeAsOSVersion": "Usa il codice versione dell'app come versione rilevata dal sistema operativo",
"requestHeader": "Intestazione della richiesta", "requestHeader": "Intestazione della richiesta",
"useLatestAssetDateAsReleaseDate": "Utilizza l'ultimo caricamento della risorsa come data di rilascio", "useLatestAssetDateAsReleaseDate": "Usa l'ultimo caricamento della risorsa come data di rilascio",
"defaultPseudoVersioningMethod": "Metodo di pseudoversione predefinito", "defaultPseudoVersioningMethod": "Metodo di pseudoversione predefinito",
"partialAPKHash": "Hash APK parziale", "partialAPKHash": "Hash APK parziale",
"APKLinkHash": "Hash collegamento APK", "APKLinkHash": "Hash collegamento APK",
@@ -298,8 +297,9 @@
"installed": "Installato", "installed": "Installato",
"latest": "Ultimo", "latest": "Ultimo",
"invertRegEx": "Inverti espressione regolare", "invertRegEx": "Inverti espressione regolare",
"note": "Note", "note": "Nota",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Il menu a tendina \"{}\" può essere usato per raggiungere istanze autogestite/personali di qualsiasi fonte.",
"badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} e un'altra app potrebbero essere state aggiornate.", "one": "{} e un'altra app potrebbero essere state aggiornate.",
"other": "{} e altre {} app potrebbero essere state aggiornate." "other": "{} e altre {} app potrebbero essere state aggiornate."
},
"apk": {
"one": "{} APK",
"other": "{} APK"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "アップデートが存在するアプリのフィルターを解除", "removeOutdatedFilter": "アップデートが存在するアプリのフィルターを解除",
"showOutdatedOnly": "アップデートが存在するアプリのみ表示する", "showOutdatedOnly": "アップデートが存在するアプリのみ表示する",
"filter": "フィルター", "filter": "フィルター",
"filterActive": "フィルター *",
"filterApps": "アプリをフィルタリングする", "filterApps": "アプリをフィルタリングする",
"appName": "アプリ名", "appName": "アプリ名",
"author": "作者", "author": "作者",
@@ -298,8 +297,9 @@
"installed": "インストール済み", "installed": "インストール済み",
"latest": "最新", "latest": "最新",
"invertRegEx": "正規表現を反転", "invertRegEx": "正規表現を反転",
"note": "Note", "note": "",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "ドロップダウン\"{}\"を使用すると、あらゆるソースのセルフホスト/カスタムインスタンスにアクセスできます。",
"badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。", "one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。" "other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
},
"apk": {
"one": "{}APK",
"other": "{}APK"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Verwijder out-of-date app filter", "removeOutdatedFilter": "Verwijder out-of-date app filter",
"showOutdatedOnly": "Toon alleen out-of-date apps", "showOutdatedOnly": "Toon alleen out-of-date apps",
"filter": "Filter", "filter": "Filter",
"filterActive": "Filteren *",
"filterApps": "Filter apps", "filterApps": "Filter apps",
"appName": "App naam", "appName": "App naam",
"author": "Auteur", "author": "Auteur",
@@ -298,8 +297,9 @@
"installed": "Geïnstalleerd", "installed": "Geïnstalleerd",
"latest": "Laatste", "latest": "Laatste",
"invertRegEx": "Reguliere expressie omkeren", "invertRegEx": "Reguliere expressie omkeren",
"note": "Note", "note": "Opmerking",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "De \"{}\" dropdown kan gebruikt worden om zelf gehoste/aangepaste instanties van elke bron te bereiken.",
"badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} en nog 1 app zijn mogelijk bijgewerkt.", "one": "{} en nog 1 app zijn mogelijk bijgewerkt.",
"other": "{} en {} meer apps zijn mogelijk bijgwerkt." "other": "{} en {} meer apps zijn mogelijk bijgwerkt."
},
"apk": {
"one": "{} APK",
"other": "{} APK's"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Usuń filtr nieaktualnych aplikacji", "removeOutdatedFilter": "Usuń filtr nieaktualnych aplikacji",
"showOutdatedOnly": "Pokaż tylko nieaktualne aplikacje", "showOutdatedOnly": "Pokaż tylko nieaktualne aplikacje",
"filter": "FIltr", "filter": "FIltr",
"filterActive": "Filtruj *",
"filterApps": "Filtruj aplikacje", "filterApps": "Filtruj aplikacje",
"appName": "Nazwa aplikacji", "appName": "Nazwa aplikacji",
"author": "Autor", "author": "Autor",
@@ -298,8 +297,9 @@
"installed": "Zainstalowano", "installed": "Zainstalowano",
"latest": "Najnowszy", "latest": "Najnowszy",
"invertRegEx": "Odwróć wyrażenie regularne", "invertRegEx": "Odwróć wyrażenie regularne",
"note": "Note", "note": "Uwaga",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Lista rozwijana \"{}\" może być używana do uzyskiwania dostępu do samodzielnie hostowanych / niestandardowych instancji dowolnego źródła.",
"badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",
@@ -377,5 +377,9 @@
"few": "{} i {} inne apki mogły zostać zaktualizowane.", "few": "{} i {} inne apki mogły zostać zaktualizowane.",
"many": "{} i {} innych apek mogło zostać zaktualizowanych.", "many": "{} i {} innych apek mogło zostać zaktualizowanych.",
"other": "{} i {} inne apki mogły zostać zaktualizowane." "other": "{} i {} inne apki mogły zostać zaktualizowane."
},
"apk": {
"one": "{} APK",
"other": "{} APK"
} }
} }

View File

@@ -11,7 +11,7 @@
"unexpectedError": "Erro inesperado", "unexpectedError": "Erro inesperado",
"ok": "OK", "ok": "OK",
"and": "e", "and": "e",
"githubPATLabel": "Token de acesso pessoal do GitHub (Reduz tempos de espera)", "githubPATLabel": "Token de acesso pessoal do GitHub\n(Reduz tempos de espera)",
"includePrereleases": "Incluir pré-lançamentos", "includePrereleases": "Incluir pré-lançamentos",
"fallbackToOlderReleases": "Retornar para versões anteriores", "fallbackToOlderReleases": "Retornar para versões anteriores",
"filterReleaseTitlesByRegEx": "Filtrar títulos de versões usando expressão regular", "filterReleaseTitlesByRegEx": "Filtrar títulos de versões usando expressão regular",
@@ -22,14 +22,14 @@
"requiredInBrackets": "(Necessário)", "requiredInBrackets": "(Necessário)",
"dropdownNoOptsError": "ERRO: O DROPDOWN DEVE TER PELO MENOS UMA OPÇÃO", "dropdownNoOptsError": "ERRO: O DROPDOWN DEVE TER PELO MENOS UMA OPÇÃO",
"colour": "Cor", "colour": "Cor",
"githubStarredRepos": "Com estrela no GitHub", "githubStarredRepos": "repositórios favoritos no GitHub",
"uname": "Nome de usuário", "uname": "Nome de usuário",
"wrongArgNum": "Número de argumentos errado", "wrongArgNum": "Número de argumentos errado",
"xIsTrackOnly": "{} é 'Apenas para monitorar'", "xIsTrackOnly": "{} é 'Apenas monitorar'",
"source": "Fonte", "source": "Fonte",
"app": "Aplicativo", "app": "Aplicativo",
"appsFromSourceAreTrackOnly": "Os aplicativos desta fonte são 'Apenas para monitorar'.", "appsFromSourceAreTrackOnly": "Os aplicativos desta fonte são 'Apenas monitorar'.",
"youPickedTrackOnly": "Você selecionou a opção 'Apenas para monitorar'.", "youPickedTrackOnly": "Você selecionou a opção 'Apenas monitorar'.",
"trackOnlyAppDescription": "As atualizações desse aplicativo serão monitoradas, mas o Obtainium não poderá baixá-lo ou instalá-lo.", "trackOnlyAppDescription": "As atualizações desse aplicativo serão monitoradas, mas o Obtainium não poderá baixá-lo ou instalá-lo.",
"cancelled": "Cancelado", "cancelled": "Cancelado",
"appAlreadyAdded": "Aplicativo já adicionado", "appAlreadyAdded": "Aplicativo já adicionado",
@@ -38,12 +38,12 @@
"appSourceURL": "URL de origem do aplicativo", "appSourceURL": "URL de origem do aplicativo",
"error": "Erro", "error": "Erro",
"add": "Adicionar", "add": "Adicionar",
"searchSomeSourcesLabel": "Procurar (Apenas algumas fontes)", "searchSomeSourcesLabel": "Procurar (apenas algumas fontes)",
"search": "Procurar", "search": "Procurar",
"additionalOptsFor": "Opções adicionais para {}", "additionalOptsFor": "Opções adicionais para {}",
"supportedSources": "Fontes compatíveis", "supportedSources": "Fontes compatíveis",
"trackOnlyInBrackets": "(Apenas para monitorar)", "trackOnlyInBrackets": "(apenas monitorar)",
"searchableInBrackets": "(Pesquisável)", "searchableInBrackets": "(pesquisável)",
"appsString": "Aplicativos", "appsString": "Aplicativos",
"noApps": "Não há aplicativos", "noApps": "Não há aplicativos",
"noAppsForFilter": "Sem aplicativos para filtrar", "noAppsForFilter": "Sem aplicativos para filtrar",
@@ -60,7 +60,7 @@
"removeSelectedApps": "Remover aplicativos selecionados", "removeSelectedApps": "Remover aplicativos selecionados",
"updateX": "Atualizar {}", "updateX": "Atualizar {}",
"installX": "Instalar {}", "installX": "Instalar {}",
"markXTrackOnlyAsUpdated": "Marcar {}\n(Apenas para monitorar)\ncomo Atualizado", "markXTrackOnlyAsUpdated": "Marcar {}\n(Apenas monitorar)\ncomo Atualizado",
"changeX": "Mudar {}", "changeX": "Mudar {}",
"installUpdateApps": "Instalar/Atualizar aplicativos", "installUpdateApps": "Instalar/Atualizar aplicativos",
"installUpdateSelectedApps": "Instalar/Atualizar aplicativos selecionados", "installUpdateSelectedApps": "Instalar/Atualizar aplicativos selecionados",
@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Remover filtro de aplicativos desatualizados", "removeOutdatedFilter": "Remover filtro de aplicativos desatualizados",
"showOutdatedOnly": "Mostrar apenas aplicativos desatualizados", "showOutdatedOnly": "Mostrar apenas aplicativos desatualizados",
"filter": "Filtro", "filter": "Filtro",
"filterActive": "Filtro *",
"filterApps": "Filtrar aplicativos", "filterApps": "Filtrar aplicativos",
"appName": "Nome do aplicativo", "appName": "Nome do aplicativo",
"author": "Autor", "author": "Autor",
@@ -89,15 +88,15 @@
"importExport": "Importar/Exportar", "importExport": "Importar/Exportar",
"settings": "Configurações", "settings": "Configurações",
"exportedTo": "Exportado para {}", "exportedTo": "Exportado para {}",
"obtainiumExport": "Exportar Obtainium", "obtainiumExport": "Exportar dados do Obtainium",
"invalidInput": "Entrada inválida", "invalidInput": "Entrada inválida",
"importedX": "Importado {}", "importedX": "Importado {}",
"obtainiumImport": "Importar Obtainium", "obtainiumImport": "Importar dados do Obtainium",
"importFromURLList": "Importar de lista de URLs", "importFromURLList": "Importar de lista de URLs",
"searchQuery": "Pesquisa", "searchQuery": "Pesquisa",
"appURLList": "Lista de URLs de aplicativos", "appURLList": "Lista de URLs de aplicativos",
"line": "Linha", "line": "Linha",
"searchX": "Pesquisa {}", "searchX": "Pesquisar na/o {}",
"noResults": "Nenhum resultado encontrado", "noResults": "Nenhum resultado encontrado",
"importX": "Importar {}", "importX": "Importar {}",
"importedAppsIdDisclaimer": "Aplicativos Importados podem ser mostrados incorretamente como \"Não Instalado\".\nPara consertar, reinstale-os usando o Obtainium.\nIsso não deve afetar dados do aplicativo.\n\nAfeta apenas métodos de importação de URL e de terceiros.", "importedAppsIdDisclaimer": "Aplicativos Importados podem ser mostrados incorretamente como \"Não Instalado\".\nPara consertar, reinstale-os usando o Obtainium.\nIsso não deve afetar dados do aplicativo.\n\nAfeta apenas métodos de importação de URL e de terceiros.",
@@ -110,8 +109,8 @@
"theme": "Tema", "theme": "Tema",
"dark": "Escuro", "dark": "Escuro",
"light": "Claro", "light": "Claro",
"followSystem": "Seguir o sistema", "followSystem": "Padrão do sistema",
"useBlackTheme": "Usar tema preto completamente escuro", "useBlackTheme": "Usar tema preto AMOLED",
"appSortBy": "Classificar aplicativo por", "appSortBy": "Classificar aplicativo por",
"authorName": "Autor/Nome", "authorName": "Autor/Nome",
"nameAuthor": "Nome/Autor", "nameAuthor": "Nome/Autor",
@@ -122,10 +121,10 @@
"bgUpdateCheckInterval": "Intervalo de verificação de atualizações em segundo-plano", "bgUpdateCheckInterval": "Intervalo de verificação de atualizações em segundo-plano",
"neverManualOnly": "Nunca - apenas manual", "neverManualOnly": "Nunca - apenas manual",
"appearance": "Aparência", "appearance": "Aparência",
"showWebInAppView": "Mostrar página da web do aplicativo em informações do aplicativo", "showWebInAppView": "Mostrar página web do aplicativo em informações do aplicativo",
"pinUpdates": "Fixar atualizações no topo da janela de aplicativos", "pinUpdates": "Fixar atualizações no topo da janela de aplicativos",
"updates": "Atualizações", "updates": "Atualizações",
"sourceSpecific": "Específico a fonte", "sourceSpecific": "Token de acesso",
"appSource": "Fonte do aplicativo", "appSource": "Fonte do aplicativo",
"noLogs": "Sem logs", "noLogs": "Sem logs",
"appLogs": "Logs do aplicativo", "appLogs": "Logs do aplicativo",
@@ -157,7 +156,7 @@
"checkingForUpdates": "Verificando atualizações", "checkingForUpdates": "Verificando atualizações",
"checkingForUpdatesNotifDescription": "Notificação transiente que aparece quando o Obtainium está verificando se há atualizações", "checkingForUpdatesNotifDescription": "Notificação transiente que aparece quando o Obtainium está verificando se há atualizações",
"pleaseAllowInstallPerm": "Por favor, permita que o Obtainium possa instalar aplicativos", "pleaseAllowInstallPerm": "Por favor, permita que o Obtainium possa instalar aplicativos",
"trackOnly": "Apenas para monitorar", "trackOnly": "Apenas monitorar",
"errorWithHttpStatusCode": "Erro {}", "errorWithHttpStatusCode": "Erro {}",
"versionCorrectionDisabled": "Correção de versão desativada (plugin parece não funcionar)", "versionCorrectionDisabled": "Correção de versão desativada (plugin parece não funcionar)",
"unknown": "Desconhecido", "unknown": "Desconhecido",
@@ -206,9 +205,9 @@
"onlyWorksWithNonVersionDetectApps": "Apenas funciona para aplicativos com detecção de versão desativada.", "onlyWorksWithNonVersionDetectApps": "Apenas funciona para aplicativos com detecção de versão desativada.",
"releaseDateAsVersion": "Usar data de lançamento como versão", "releaseDateAsVersion": "Usar data de lançamento como versão",
"releaseDateAsVersionExplanation": "Esta opção só deve ser usada para aplicativos onde a detecção de versão não funciona corretamente, mas há uma data de lançamento disponível.", "releaseDateAsVersionExplanation": "Esta opção só deve ser usada para aplicativos onde a detecção de versão não funciona corretamente, mas há uma data de lançamento disponível.",
"changes": "Mudanças", "changes": "Alterações",
"releaseDate": "Data de lançamento", "releaseDate": "Data de lançamento",
"importFromURLsInFile": "Importar de URLs em arquivo (como OPML)", "importFromURLsInFile": "Importar de URLs em arquivo (formato OPML)",
"versionDetectionExplanation": "Reconciliar string de versão com versão detectada no sistema operacional", "versionDetectionExplanation": "Reconciliar string de versão com versão detectada no sistema operacional",
"versionDetection": "Detecção de versão", "versionDetection": "Detecção de versão",
"standardVersionDetection": "Detecção de versão padrão", "standardVersionDetection": "Detecção de versão padrão",
@@ -216,7 +215,7 @@
"autoApkFilterByArch": "Tente filtrar APKs por arquitetura de CPU, se possível", "autoApkFilterByArch": "Tente filtrar APKs por arquitetura de CPU, se possível",
"overrideSource": "Substituir fonte", "overrideSource": "Substituir fonte",
"dontShowAgain": "Não mostrar isso novamente", "dontShowAgain": "Não mostrar isso novamente",
"dontShowTrackOnlyWarnings": "Não mostrar avisos 'Apenas para monitorar'", "dontShowTrackOnlyWarnings": "Não mostrar avisos 'Apenas monitorar'",
"dontShowAPKOriginWarnings": "Não mostrar avisos de origem da APK", "dontShowAPKOriginWarnings": "Não mostrar avisos de origem da APK",
"moveNonInstalledAppsToBottom": "Mover aplicativos não instalados para o fundo da lista de aplicativos", "moveNonInstalledAppsToBottom": "Mover aplicativos não instalados para o fundo da lista de aplicativos",
"gitlabPATLabel": "Token de acesso pessoal do Gitlab\n(Ativa pesquisa e melhora a descoberta de APKs)", "gitlabPATLabel": "Token de acesso pessoal do Gitlab\n(Ativa pesquisa e melhora a descoberta de APKs)",
@@ -228,7 +227,7 @@
"pickHighestVersionCode": "Auto-selecionar o maior número de versão do APK", "pickHighestVersionCode": "Auto-selecionar o maior número de versão do APK",
"checkUpdateOnDetailPage": "Checar por atualizações ao abrir a página de detalhes de um aplicativo", "checkUpdateOnDetailPage": "Checar por atualizações ao abrir a página de detalhes de um aplicativo",
"disablePageTransitions": "Desativar animações de transição de página", "disablePageTransitions": "Desativar animações de transição de página",
"reversePageTransitions": "Reverter animações de transição de página", "reversePageTransitions": "Animações de transição de página invertidas",
"minStarCount": "Contagem mínima de estrelas", "minStarCount": "Contagem mínima de estrelas",
"addInfoBelow": "Adicionar essa informação abaixo.", "addInfoBelow": "Adicionar essa informação abaixo.",
"addInfoInSettings": "Adicionar essa informação nas configurações.", "addInfoInSettings": "Adicionar essa informação nas configurações.",
@@ -254,7 +253,7 @@
"versionExtractionRegEx": "Regex de extração de versão", "versionExtractionRegEx": "Regex de extração de versão",
"matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão", "matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão",
"highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias", "highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias",
"pickExportDir": "Escolher diretório para a exportação", "pickExportDir": "Escolher diretório para exportação",
"autoExportOnChanges": "Auto-exportar em mudanças", "autoExportOnChanges": "Auto-exportar em mudanças",
"includeSettings": "Incluir configurações", "includeSettings": "Incluir configurações",
"filterVersionsByRegEx": "Filtrar versões por expressão regular", "filterVersionsByRegEx": "Filtrar versões por expressão regular",
@@ -298,8 +297,9 @@
"installed": "Instalado", "installed": "Instalado",
"latest": "Mais recente", "latest": "Mais recente",
"invertRegEx": "Inverter expressão regular", "invertRegEx": "Inverter expressão regular",
"note": "Note", "note": "Nota",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "O menu suspenso \"{}\" pode ser usado para acessar instâncias auto-hospedadas/personalizadas de qualquer fonte.",
"badDownload": "Não foi possível analisar o APK (transferência incompatível ou parcial)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicativo?", "one": "Remover aplicativo?",
"other": "Remover aplicativos?" "other": "Remover aplicativos?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} e um outro aplicativo podem ter sido atualizados.", "one": "{} e um outro aplicativo podem ter sido atualizados.",
"other": "{} e {} outros aplicativos podem ter sido atualizados." "other": "{} e {} outros aplicativos podem ter sido atualizados."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Удалить фильтр для устаревших приложений", "removeOutdatedFilter": "Удалить фильтр для устаревших приложений",
"showOutdatedOnly": "Показывать только устаревшие приложения", "showOutdatedOnly": "Показывать только устаревшие приложения",
"filter": "Фильтр", "filter": "Фильтр",
"filterActive": "Фильтр *",
"filterApps": "Фильтровать приложения", "filterApps": "Фильтровать приложения",
"appName": "Название приложения", "appName": "Название приложения",
"author": "Автор", "author": "Автор",
@@ -298,8 +297,9 @@
"installed": "Установлен", "installed": "Установлен",
"latest": "Последний", "latest": "Последний",
"invertRegEx": "Инвертировать регулярное выражение", "invertRegEx": "Инвертировать регулярное выражение",
"note": "Note", "note": "Примечание",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Выпадающий список \"{}\" можно использовать для доступа к самостоятельно размещенным/настроенным экземплярам любого источника.",
"badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} и ещё 1 приложение могли быть обновлены", "one": "{} и ещё 1 приложение могли быть обновлены",
"other": "{} и ещё {} приложений могли быть обновлены" "other": "{} и ещё {} приложений могли быть обновлены"
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -1,30 +1,118 @@
// Take one (hardcoded) translation file and ensure that all other translation files have the same keys in the same order // Take one (hardcoded) translation file and ensure that all other translation files have the same keys in the same order
// Then report which other translation files have identical items // Then report which other translation files have identical items (or auto-translate them if a DeepL API key is provided)
const fs = require('fs') const fs = require('fs')
const https = require('https')
const translationsDir = __dirname const deeplAPIKey = process.argv[2]
const templateFile = `${translationsDir}/en.json`
const otherFiles = fs.readdirSync(translationsDir).map(f => {
return `${translationsDir}/${f}`
}).filter(f => f.endsWith('.json') && f != templateFile)
const templateTranslation = require(templateFile) const neverAutoTranslate = {
steamMobile: ['*'],
steamChat: ['*'],
root: ['*'],
obtainiumExportHyphenatedLowercase: ['*'],
theme: ['de'],
appId: ['de']
}
otherFiles.forEach(file => { const translateText = async (text, targetLang, authKey) => {
const thisTranslationOriginal = require(file) return new Promise((resolve, reject) => {
const thisTranslationNew = {} const postData = `text=${encodeURIComponent(text)}&target_lang=${encodeURIComponent(targetLang)}&source_lang=EN`
Object.keys(templateTranslation).forEach(k => { const options = {
thisTranslationNew[k] = thisTranslationOriginal[k] || templateTranslation[k] hostname: 'api-free.deepl.com',
}) port: 443,
fs.writeFileSync(file, `${JSON.stringify(thisTranslationNew, null, ' ')}\n`) path: '/v2/translate',
}); method: 'POST',
headers: {
otherFiles.forEach(file => { 'Authorization': `DeepL-Auth-Key ${authKey}`,
const thisTranslation = require(file) 'Content-Type': 'application/x-www-form-urlencoded',
Object.keys(templateTranslation).forEach(k => { 'Content-Length': Buffer.byteLength(postData)
if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) { }
console.log(`${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`)
} }
const req = https.request(options, (res) => {
let responseData = ''
res.on('data', (chunk) => {
responseData += chunk
})
res.on('end', () => {
try {
const jsonResponse = JSON.parse(responseData)
resolve(jsonResponse)
} catch (error) {
reject(error)
}
})
})
req.on('error', (error) => {
reject(error)
})
req.write(postData)
req.end()
}) })
}); }
const main = async () => {
const translationsDir = __dirname
const templateFile = `${translationsDir}/en.json`
const otherFiles = fs.readdirSync(translationsDir).map(f => {
return `${translationsDir}/${f}`
}).filter(f => f.endsWith('.json') && f != templateFile)
const templateTranslation = JSON.parse(fs.readFileSync(templateFile).toString())
otherFiles.forEach(file => {
const thisTranslationOriginal = JSON.parse(fs.readFileSync((file).toString()))
const thisTranslationNew = {}
Object.keys(templateTranslation).forEach(k => {
thisTranslationNew[k] = thisTranslationOriginal[k] || templateTranslation[k]
})
fs.writeFileSync(file, `${JSON.stringify(thisTranslationNew, null, ' ')}\n`)
})
for (let i in otherFiles) {
const file = otherFiles[i]
const thisTranslation = JSON.parse(fs.readFileSync((file).toString()))
const translationKeys = Object.keys(templateTranslation)
for (let j in translationKeys) {
const k = translationKeys[j]
if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) {
const lang = file.split('/').pop().split('.')[0]
if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) {
const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}`
if (deeplAPIKey) {
const translateFunc = async (str) => {
const response = await translateText(str, lang, deeplAPIKey)
if (response.translations) {
return response.translations[0].text
} else {
throw JSON.stringify(response)
}
}
try {
if (typeof templateTranslation[k] == 'string') {
thisTranslation[k] = await translateFunc(thisTranslation[k])
} else {
const subKeys = Object.keys(templateTranslation[k])
for (let n in subKeys) {
const kk = subKeys[n]
thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk])
}
}
} catch (e) {
if (typeof e == 'string') {
console.log(`${reportLine} :::: ${e}`)
} else {
throw e
}
}
} else {
console.log(reportLine)
}
}
}
}
fs.writeFileSync(file, `${JSON.stringify(thisTranslation, null, ' ')}\n`)
}
}
main().catch(e => console.error)

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Ta bort Utgånga App-filtret", "removeOutdatedFilter": "Ta bort Utgånga App-filtret",
"showOutdatedOnly": "Visa Endast Utgånga Appar", "showOutdatedOnly": "Visa Endast Utgånga Appar",
"filter": "Filtrera", "filter": "Filtrera",
"filterActive": "Filter *",
"filterApps": "Filtrera Appar", "filterApps": "Filtrera Appar",
"appName": "Appnamn", "appName": "Appnamn",
"author": "Utvecklare", "author": "Utvecklare",
@@ -288,18 +287,19 @@
"useSystemFont": "Använd systemteckensnittet", "useSystemFont": "Använd systemteckensnittet",
"systemFontError": "Fel vid laddning av systemteckensnittet: {}", "systemFontError": "Fel vid laddning av systemteckensnittet: {}",
"useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version", "useVersionCodeAsOSVersion": "Använd appversionskoden som OS-upptäckt version",
"requestHeader": "Request header", "requestHeader": "Rubrik för begäran",
"useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum", "useLatestAssetDateAsReleaseDate": "Använd senaste tillgångsuppladdning som releasedatum",
"defaultPseudoVersioningMethod": "Standard pseudoversionsmetod", "defaultPseudoVersioningMethod": "Standard pseudoversionsmetod",
"partialAPKHash": "Delvis APK-hash", "partialAPKHash": "Delvis APK-hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK-länk Hash",
"directAPKLink": "Direkt APK-länk", "directAPKLink": "Direkt APK-länk",
"pseudoVersionInUse": "En pseudoversion används", "pseudoVersionInUse": "En pseudoversion används",
"installed": "Installerad", "installed": "Installerad",
"latest": "Senast", "latest": "Senast",
"invertRegEx": "Invertera reguljärt uttryck", "invertRegEx": "Invertera reguljärt uttryck",
"note": "Note", "note": "Anmärkning",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Rullgardinsmenyn \"{}\" kan användas för att nå självhostade/anpassade instanser av valfri källa.",
"badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} och 1 till app kan ha uppdaterats.", "one": "{} och 1 till app kan ha uppdaterats.",
"other": "{} och {} appar till kan ha uppdaterats." "other": "{} och {} appar till kan ha uppdaterats."
},
"apk": {
"one": "{} APK",
"other": "{} APK:er"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "Güncel Olmayan Uygulama Filtresini Kaldır", "removeOutdatedFilter": "Güncel Olmayan Uygulama Filtresini Kaldır",
"showOutdatedOnly": "Yalnızca Güncel Olmayan Uygulamaları Göster", "showOutdatedOnly": "Yalnızca Güncel Olmayan Uygulamaları Göster",
"filter": "Filtre", "filter": "Filtre",
"filterActive": "Filtre *",
"filterApps": "Uygulamaları Filtrele", "filterApps": "Uygulamaları Filtrele",
"appName": "Uygulama Adı", "appName": "Uygulama Adı",
"author": "Yazar", "author": "Yazar",
@@ -298,8 +297,9 @@
"installed": "Kurulmuş", "installed": "Kurulmuş",
"latest": "En sonuncu", "latest": "En sonuncu",
"invertRegEx": "Normal ifadeyi ters çevir", "invertRegEx": "Normal ifadeyi ters çevir",
"note": "Note", "note": "Not",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "\"{}\" ılır menüsü, herhangi bir kaynağın kendi kendine barındırılan/özel örneklerine ulaşmak için kullanılabilir.",
"badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} ve 1 diğer uygulama muhtemelen güncellendi.", "one": "{} ve 1 diğer uygulama muhtemelen güncellendi.",
"other": "{} ve {} daha fazla uygulama muhtemelen güncellendi." "other": "{} ve {} daha fazla uygulama muhtemelen güncellendi."
},
"apk": {
"one": "{} APK",
"other": "{} APK'lar"
} }
} }

View File

@@ -72,7 +72,7 @@
"unpinFromTop": "Bỏ ghim khỏi đầu trang", "unpinFromTop": "Bỏ ghim khỏi đầu trang",
"resetInstallStatusForSelectedAppsQuestion": "Đặt lại trạng thái cài đặt cho ứng dụng đã chọn?", "resetInstallStatusForSelectedAppsQuestion": "Đặt lại trạng thái cài đặt cho ứng dụng đã chọn?",
"installStatusOfXWillBeResetExplanation": "Trạng thái cài đặt của mọi Ứng dụng đã chọn sẽ được đặt lại.\n\nĐiều này có thể hữu ích khi phiên bản Ứng dụng hiển thị trong Obtainium không chính xác do cập nhật không thành công hoặc các sự cố khác.", "installStatusOfXWillBeResetExplanation": "Trạng thái cài đặt của mọi Ứng dụng đã chọn sẽ được đặt lại.\n\nĐiều này có thể hữu ích khi phiên bản Ứng dụng hiển thị trong Obtainium không chính xác do cập nhật không thành công hoặc các sự cố khác.",
"customLinkMessage": "Các liên kết này hoạt động trên các thiết bị có cài đặt Gainium", "customLinkMessage": "Các liên kết này hoạt động trên các thiết bị có cài đặt Obtainium",
"shareAppConfigLinks": "Chia sẻ cấu hình ứng dụng dưới dạng liên kết HTML", "shareAppConfigLinks": "Chia sẻ cấu hình ứng dụng dưới dạng liên kết HTML",
"shareSelectedAppURLs": "Chia sẻ URL ứng dụng đã chọn", "shareSelectedAppURLs": "Chia sẻ URL ứng dụng đã chọn",
"resetInstallStatus": "Đặt lại trạng thái cài đặt", "resetInstallStatus": "Đặt lại trạng thái cài đặt",
@@ -80,14 +80,13 @@
"removeOutdatedFilter": "Xóa bộ lọc ứng dụng lỗi thời", "removeOutdatedFilter": "Xóa bộ lọc ứng dụng lỗi thời",
"showOutdatedOnly": "Chỉ hiển thị các ứng dụng lỗi thời", "showOutdatedOnly": "Chỉ hiển thị các ứng dụng lỗi thời",
"filter": "Lọc", "filter": "Lọc",
"filterActive": "Lọc *",
"filterApps": "Lọc ứng dụng", "filterApps": "Lọc ứng dụng",
"appName": "Tên ứng dụng", "appName": "Tên ứng dụng",
"author": "Tác giả", "author": "Tác giả",
"upToDateApps": "Ứng dụng cập nhật", "upToDateApps": "Ứng dụng cập nhật",
"nonInstalledApps": "Ứng dụng chưa được cài đặt", "nonInstalledApps": "Ứng dụng chưa được cài đặt",
"importExport": "Nhập/Xuất", "importExport": "Nhập/Xuất",
"settings": "Cài đặt", "settings": "Thiết đặt",
"exportedTo": "Đã xuất sang {}", "exportedTo": "Đã xuất sang {}",
"obtainiumExport": "Xuất", "obtainiumExport": "Xuất",
"invalidInput": "Đầu vào không hợp lệ", "invalidInput": "Đầu vào không hợp lệ",
@@ -132,7 +131,7 @@
"close": "Đóng", "close": "Đóng",
"share": "Chia sẻ", "share": "Chia sẻ",
"appNotFound": "Không tìm thấy ứng dụng", "appNotFound": "Không tìm thấy ứng dụng",
"obtainiumExportHyphenatedLowercase": "xuất khẩu-obtainium", "obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "Chọn một APK", "pickAnAPK": "Chọn một APK",
"appHasMoreThanOnePackage": "{} có nhiều gói:", "appHasMoreThanOnePackage": "{} có nhiều gói:",
"deviceSupportsXArch": "Thiết bị của bạn hỗ trợ kiến trúc CPU {}.", "deviceSupportsXArch": "Thiết bị của bạn hỗ trợ kiến trúc CPU {}.",
@@ -168,7 +167,7 @@
"lastUpdateCheckX": "Kiểm tra cập nhật lần cuối: {}", "lastUpdateCheckX": "Kiểm tra cập nhật lần cuối: {}",
"remove": "Loại bỏ", "remove": "Loại bỏ",
"yesMarkUpdated": "Có, Đánh dấu là đã cập nhật", "yesMarkUpdated": "Có, Đánh dấu là đã cập nhật",
"fdroid": "Chính thức của F-Droid", "fdroid": "F-Droid Chính thức",
"appIdOrName": "ID hoặc tên ứng dụng", "appIdOrName": "ID hoặc tên ứng dụng",
"appId": "ID ứng dụng", "appId": "ID ứng dụng",
"appWithIdOrNameNotFound": "Không tìm thấy ứng dụng nào có ID hoặc tên đó", "appWithIdOrNameNotFound": "Không tìm thấy ứng dụng nào có ID hoặc tên đó",
@@ -188,18 +187,18 @@
"noAPKFound": "Không tìm thấy APK", "noAPKFound": "Không tìm thấy APK",
"noVersionDetection": "Không phát hiện phiên bản", "noVersionDetection": "Không phát hiện phiên bản",
"categorize": "Phân loại", "categorize": "Phân loại",
"categories": "Thể loại", "categories": "Danh mục",
"category": "Thể loại", "category": "Danh mục",
"noCategory": "Không thể loại", "noCategory": "Không danh mục",
"noCategories": "Không thể loại", "noCategories": "Không danh mục",
"deleteCategoriesQuestion": "Xóa thể loại?", "deleteCategoriesQuestion": "Xóa danh mục?",
"categoryDeleteWarning": "Tất cả ứng dụng trong thể loại đã xóa sẽ được đặt thành chưa được phân loại.", "categoryDeleteWarning": "Tất cả ứng dụng trong danh mục đã xóa sẽ được đặt thành chưa được phân loại.",
"addCategory": "Thêm thể loại", "addCategory": "Thêm thể loại",
"label": "Nhãn", "label": "Nhãn",
"language": "Ngôn ngữ", "language": "Ngôn ngữ",
"copiedToClipboard": "Sao chép vào clipboard", "copiedToClipboard": "Sao chép vào clipboard",
"storagePermissionDenied": "Quyền lưu trữ bị từ chối", "storagePermissionDenied": "Quyền lưu trữ bị từ chối",
"selectedCategorizeWarning": "Điều này sẽ thay thế mọi cài đặt thể loại hiện có cho Ứng dụng đã chọn.", "selectedCategorizeWarning": "Điều này sẽ thay thế mọi thiết đặt danh mục hiện có cho Ứng dụng đã chọn.",
"filterAPKsByRegEx": "Lọc APK theo biểu thức chính quy", "filterAPKsByRegEx": "Lọc APK theo biểu thức chính quy",
"removeFromObtainium": "Loại khỏi Obtainium", "removeFromObtainium": "Loại khỏi Obtainium",
"uninstallFromDevice": "Gỡ cài đặt khỏi thiết bị", "uninstallFromDevice": "Gỡ cài đặt khỏi thiết bị",
@@ -212,7 +211,7 @@
"versionDetectionExplanation": "Đối chiếu chuỗi phiên bản với phiên bản được phát hiện từ hệ điều hành", "versionDetectionExplanation": "Đối chiếu chuỗi phiên bản với phiên bản được phát hiện từ hệ điều hành",
"versionDetection": "Phát hiện phiên bản", "versionDetection": "Phát hiện phiên bản",
"standardVersionDetection": "Phát hiện phiên bản tiêu chuẩn", "standardVersionDetection": "Phát hiện phiên bản tiêu chuẩn",
"groupByCategory": "Nhóm theo thể loại", "groupByCategory": "Nhóm theo danh mục",
"autoApkFilterByArch": "Cố gắng lọc APK theo kiến trúc CPU nếu có thể", "autoApkFilterByArch": "Cố gắng lọc APK theo kiến trúc CPU nếu có thể",
"overrideSource": "Ghi đè nguồn", "overrideSource": "Ghi đè nguồn",
"dontShowAgain": "Đừng hiển thị thông tin này nữa", "dontShowAgain": "Đừng hiển thị thông tin này nữa",
@@ -221,7 +220,7 @@
"moveNonInstalledAppsToBottom": "Chuyển Ứng dụng chưa được cài đặt xuống cuối danh sách", "moveNonInstalledAppsToBottom": "Chuyển Ứng dụng chưa được cài đặt xuống cuối danh sách",
"gitlabPATLabel": "GitLab Token\n(Cho phép tìm kiếm và lọc APK tốt hơn)", "gitlabPATLabel": "GitLab Token\n(Cho phép tìm kiếm và lọc APK tốt hơn)",
"about": "Giới thiệu", "about": "Giới thiệu",
"requiresCredentialsInSettings": "{}: Điều này cần thông tin xác thực bổ sung (trong Cài đặt)", "requiresCredentialsInSettings": "{}: Điều này cần thông tin xác thực bổ sung (trong Thiết đặt)",
"checkOnStart": "Kiểm tra các bản cập nhật khi khởi động", "checkOnStart": "Kiểm tra các bản cập nhật khi khởi động",
"tryInferAppIdFromCode": "Thử suy ra ID ứng dụng từ mã nguồn", "tryInferAppIdFromCode": "Thử suy ra ID ứng dụng từ mã nguồn",
"removeOnExternalUninstall": "Tự động xóa ứng dụng đã gỡ cài đặt bên ngoài", "removeOnExternalUninstall": "Tự động xóa ứng dụng đã gỡ cài đặt bên ngoài",
@@ -231,7 +230,7 @@
"reversePageTransitions": "Hoạt ảnh chuyển đổi trang đảo ngược", "reversePageTransitions": "Hoạt ảnh chuyển đổi trang đảo ngược",
"minStarCount": "Số lượng sao tối thiểu", "minStarCount": "Số lượng sao tối thiểu",
"addInfoBelow": "Thêm thông tin này vào bên dưới.", "addInfoBelow": "Thêm thông tin này vào bên dưới.",
"addInfoInSettings": "Thêm thông tin này vào Cài đặt.", "addInfoInSettings": "Thêm thông tin này vào Thiết đặt.",
"githubSourceNote": "Có thể tránh được việc giới hạn tốc độ GitHub bằng cách sử dụng khóa API.", "githubSourceNote": "Có thể tránh được việc giới hạn tốc độ GitHub bằng cách sử dụng khóa API.",
"gitlabSourceNote": "Trích xuất APK GitLab có thể không hoạt động nếu không có khóa API.", "gitlabSourceNote": "Trích xuất APK GitLab có thể không hoạt động nếu không có khóa API.",
"sortByLastLinkSegment": "Chỉ sắp xếp theo đoạn cuối của liên kết", "sortByLastLinkSegment": "Chỉ sắp xếp theo đoạn cuối của liên kết",
@@ -256,7 +255,7 @@
"highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn", "highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn",
"pickExportDir": "Chọn thư mục xuất", "pickExportDir": "Chọn thư mục xuất",
"autoExportOnChanges": "Tự động xuất", "autoExportOnChanges": "Tự động xuất",
"includeSettings": "Bao gồm cài đặt ứng dụng", "includeSettings": "Bao gồm thiết đặt",
"filterVersionsByRegEx": "Lọc phiên bản theo biểu thức chính quy", "filterVersionsByRegEx": "Lọc phiên bản theo biểu thức chính quy",
"trySelectingSuggestedVersionCode": "Thử chọn APK Mã phiên bản được đề xuất", "trySelectingSuggestedVersionCode": "Thử chọn APK Mã phiên bản được đề xuất",
"dontSortReleasesList": "Giữ lại thứ tự phát hành từ API", "dontSortReleasesList": "Giữ lại thứ tự phát hành từ API",
@@ -298,8 +297,9 @@
"installed": "Đã cài đặt", "installed": "Đã cài đặt",
"latest": "Mới nhất", "latest": "Mới nhất",
"invertRegEx": "Đảo ngược biểu thức chính quy", "invertRegEx": "Đảo ngược biểu thức chính quy",
"note": "Note", "note": "Ghi chú",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "Trình đơn thả xuống \"{}\" có thể được dùng để tiếp cận các phiên bản tự lưu trữ/tùy chỉnh của bất kỳ nguồn nào.",
"badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} và 1 ứng dụng khác có thể đã được cập nhật.", "one": "{} và 1 ứng dụng khác có thể đã được cập nhật.",
"other": "{} và {} ứng dụng khác có thể đã được cập nhật." "other": "{} và {} ứng dụng khác có thể đã được cập nhật."
},
"apk": {
"one": "{} APK",
"other": "{} APKs"
} }
} }

View File

@@ -80,7 +80,6 @@
"removeOutdatedFilter": "删除失效的应用筛选", "removeOutdatedFilter": "删除失效的应用筛选",
"showOutdatedOnly": "只显示待更新应用", "showOutdatedOnly": "只显示待更新应用",
"filter": "筛选", "filter": "筛选",
"filterActive": "筛选 *",
"filterApps": "筛选应用", "filterApps": "筛选应用",
"appName": "应用名称", "appName": "应用名称",
"author": "作者", "author": "作者",
@@ -298,8 +297,9 @@
"installed": "已安装", "installed": "已安装",
"latest": "最新的", "latest": "最新的",
"invertRegEx": "反转正则表达式", "invertRegEx": "反转正则表达式",
"note": "Note", "note": "备注",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "{}\"下拉菜单可用于访问任何来源的自托管/自定义实例。",
"badDownload": "无法解析 APK不兼容或部分下载",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"
@@ -351,5 +351,9 @@
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} 和另外 1 个应用已尝试更新。", "one": "{} 和另外 1 个应用已尝试更新。",
"other": "“{}”和另外 {} 个应用已尝试更新。" "other": "“{}”和另外 {} 个应用已尝试更新。"
},
"apk": {
"one": "{}APK",
"other": "{}APK"
} }
} }

View File

@@ -76,16 +76,7 @@ class FDroid extends AppSource {
'https://$host/repo/$appId', 'https://$host/repo/$appId',
standardUrl, standardUrl,
name, name,
autoSelectHighestVersionCode: additionalSettings: additionalSettings);
additionalSettings['autoSelectHighestVersionCode'] == true,
trySelectingSuggestedVersionCode:
additionalSettings['trySelectingSuggestedVersionCode'] == true,
filterVersionsByRegEx:
(additionalSettings['filterVersionsByRegEx'] as String?)
?.isNotEmpty ==
true
? additionalSettings['filterVersionsByRegEx']
: null);
if (!hostChanged) { if (!hostChanged) {
try { try {
var res = await sourceRequest( var res = await sourceRequest(
@@ -166,12 +157,30 @@ class FDroid extends AppSource {
APKDetails getAPKUrlsFromFDroidPackagesAPIResponse( APKDetails getAPKUrlsFromFDroidPackagesAPIResponse(
Response res, String apkUrlPrefix, String standardUrl, String sourceName, Response res, String apkUrlPrefix, String standardUrl, String sourceName,
{bool autoSelectHighestVersionCode = false, {Map<String, dynamic> additionalSettings = const {}}) {
bool trySelectingSuggestedVersionCode = false, var autoSelectHighestVersionCode =
String? filterVersionsByRegEx}) { additionalSettings['autoSelectHighestVersionCode'] == true;
var trySelectingSuggestedVersionCode =
additionalSettings['trySelectingSuggestedVersionCode'] == true;
var filterVersionsByRegEx =
(additionalSettings['filterVersionsByRegEx'] as String?)?.isNotEmpty ==
true
? additionalSettings['filterVersionsByRegEx']
: null;
var apkFilterRegEx =
(additionalSettings['apkFilterRegEx'] as String?)?.isNotEmpty == true
? additionalSettings['apkFilterRegEx']
: null;
if (res.statusCode == 200) { if (res.statusCode == 200) {
var response = jsonDecode(res.body); var response = jsonDecode(res.body);
List<dynamic> releases = response['packages'] ?? []; List<dynamic> releases = response['packages'] ?? [];
if (apkFilterRegEx != null) {
releases = releases.where((rel) {
String apk = '${apkUrlPrefix}_${rel['versionCode']}.apk';
return filterApks([MapEntry(apk, apk)], apkFilterRegEx, false)
.isNotEmpty;
}).toList();
}
if (releases.isEmpty) { if (releases.isEmpty) {
throw NoReleasesError(); throw NoReleasesError();
} }

View File

@@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
@@ -45,7 +46,7 @@ class FDroidRepo extends AppSource {
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
var standardUri = Uri.parse(url); var standardUri = Uri.parse(url);
var pathSegments = standardUri.pathSegments; var pathSegments = standardUri.pathSegments;
if (pathSegments.last == 'index.xml') { if (pathSegments.isNotEmpty && pathSegments.last == 'index.xml') {
pathSegments.removeLast(); pathSegments.removeLast();
standardUri = standardUri.replace(path: pathSegments.join('/')); standardUri = standardUri.replace(path: pathSegments.join('/'));
} }
@@ -60,7 +61,7 @@ class FDroidRepo extends AppSource {
throw NoReleasesError(); throw NoReleasesError();
} }
url = removeQueryParamsFromUrl(standardizeUrl(url)); url = removeQueryParamsFromUrl(standardizeUrl(url));
var res = await sourceRequest('$url/index.xml', {}); var res = await sourceRequestWithURLVariants(url, {});
if (res.statusCode == 200) { if (res.statusCode == 200) {
var body = parse(res.body); var body = parse(res.body);
Map<String, List<String>> results = {}; Map<String, List<String>> results = {};
@@ -72,7 +73,11 @@ class FDroidRepo extends AppSource {
appId.contains(query) || appId.contains(query) ||
appName.contains(query) || appName.contains(query) ||
appDesc.contains(query)) { appDesc.contains(query)) {
results['$url?appId=$appId'] = [appName, appDesc]; results[
'${res.request!.url.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}?appId=$appId'] = [
appName,
appDesc
];
} }
}); });
return results; return results;
@@ -102,6 +107,26 @@ class FDroidRepo extends AppSource {
return app; return app;
} }
Future<Response> sourceRequestWithURLVariants(
String url,
Map<String, dynamic> additionalSettings,
) async {
var res = await sourceRequest(
'$url${url.endsWith('/index.xml') ? '' : '/index.xml'}',
additionalSettings);
if (res.statusCode != 200) {
var base = url.endsWith('/index.xml')
? url.split('/').reversed.toList().sublist(1).reversed.join('/')
: url;
res = await sourceRequest('$base/repo/index.xml', additionalSettings);
if (res.statusCode != 200) {
res = await sourceRequest(
'$base/fdroid/repo/index.xml', additionalSettings);
}
}
return res;
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,
@@ -117,9 +142,8 @@ class FDroidRepo extends AppSource {
if (appIdOrName == null) { if (appIdOrName == null) {
throw NoReleasesError(); throw NoReleasesError();
} }
var res = await sourceRequest( var res =
'$standardUrl${standardUrl.endsWith('/index.xml') ? '' : '/index.xml'}', await sourceRequestWithURLVariants(standardUrl, additionalSettings);
additionalSettings);
if (res.statusCode == 200) { if (res.statusCode == 200) {
var body = parse(res.body); var body = parse(res.body);
var foundApps = body.querySelectorAll('application').where((element) { var foundApps = body.querySelectorAll('application').where((element) {
@@ -168,7 +192,8 @@ class FDroidRepo extends AppSource {
latestVersionReleases = [latestVersionReleases[0]]; latestVersionReleases = [latestVersionReleases[0]];
} }
List<String> apkUrls = latestVersionReleases List<String> apkUrls = latestVersionReleases
.map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}') .map((e) =>
'${res.request!.url.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}/${e.querySelector('apkname')!.innerHtml}')
.toList(); .toList();
return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls), return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls),
AppNames(authorName, appName), AppNames(authorName, appName),

View File

@@ -400,7 +400,7 @@ class GitHub extends AppSource {
if (version == null) { if (version == null) {
throw NoVersionError(); throw NoVersionError();
} }
var changeLog = targetRelease['body'].toString(); var changeLog = (targetRelease['body'] ?? '').toString();
return APKDetails( return APKDetails(
version, version,
targetRelease['apkUrls'] as List<MapEntry<String, String>>, targetRelease['apkUrls'] as List<MapEntry<String, String>>,

View File

@@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
@@ -104,6 +105,21 @@ class GitLab extends AppSource {
String? changeLogPageFromStandardUrl(String standardUrl) => String? changeLogPageFromStandardUrl(String standardUrl) =>
'$standardUrl/-/releases'; '$standardUrl/-/releases';
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) async {
// Change headers to pacify, e.g. cloudflare protection
// Related to: (#1397, #1389, #1384, #1382, #1381, #1380, #1359, #854, #785, #697)
var headers = <String, String>{};
headers[HttpHeaders.refererHeader] = 'https://${hosts[0]}';
if (headers.isNotEmpty) {
return headers;
} else {
return null;
}
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,

View File

@@ -319,7 +319,7 @@ class HTML extends AppSource {
version ??= version ??=
additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash'
? rel.hashCode.toString() ? rel.hashCode.toString()
: (await checkPartialDownloadHashDynamc(rel)).toString(); : (await checkPartialDownloadHashDynamic(rel)).toString();
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(), return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
AppNames(uri.host, tr('app'))); AppNames(uri.host, tr('app')));
} }

View File

@@ -50,10 +50,6 @@ class IzzyOnDroid extends AppSource {
'https://android.izzysoft.de/frepo/$appId', 'https://android.izzysoft.de/frepo/$appId',
standardUrl, standardUrl,
name, name,
autoSelectHighestVersionCode: additionalSettings: additionalSettings);
additionalSettings['autoSelectHighestVersionCode'] == true,
trySelectingSuggestedVersionCode:
additionalSettings['trySelectingSuggestedVersionCode'] == true,
filterVersionsByRegEx: additionalSettings['filterVersionsByRegEx']);
} }
} }

View File

@@ -10,16 +10,23 @@ class SourceForge extends AppSource {
@override @override
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
RegExp standardUrlRegExB = RegExp( var sourceRegex = getSourceRegex(hosts);
'^https?://(www\\.)?${getSourceRegex(hosts)}/p/[^/]+', RegExp standardUrlRegExC =
caseSensitive: false); RegExp('^https?://(www\\.)?$sourceRegex/p/.+', caseSensitive: false);
RegExpMatch? match = standardUrlRegExB.firstMatch(url); RegExpMatch? match = standardUrlRegExC.firstMatch(url);
if (match != null) { if (match != null) {
url = url =
'https://${Uri.parse(match.group(0)!).host}/projects/${url.substring(Uri.parse(match.group(0)!).host.length + '/projects/'.length + 1)}'; 'https://${Uri.parse(match.group(0)!).host}/projects/${url.substring(Uri.parse(match.group(0)!).host.length + '/projects/'.length + 1)}';
} }
RegExp standardUrlRegExB = RegExp(
'^https?://(www\\.)?$sourceRegex/projects/[^/]+',
caseSensitive: false);
match = standardUrlRegExB.firstMatch(url);
if (match != null && match.group(0) == url) {
url = '$url/files';
}
RegExp standardUrlRegExA = RegExp( RegExp standardUrlRegExA = RegExp(
'^https?://(www\\.)?${getSourceRegex(hosts)}/projects/[^/]+', '^https?://(www\\.)?$sourceRegex/projects/[^/]+/files(/.+)?',
caseSensitive: false); caseSensitive: false);
match = standardUrlRegExA.firstMatch(url); match = standardUrlRegExA.firstMatch(url);
if (match == null) { if (match == null) {
@@ -33,38 +40,79 @@ class SourceForge extends AppSource {
String standardUrl, String standardUrl,
Map<String, dynamic> additionalSettings, Map<String, dynamic> additionalSettings,
) async { ) async {
Response res = var standardUri = Uri.parse(standardUrl);
await sourceRequest('$standardUrl/rss?path=/', additionalSettings); if (standardUri.pathSegments.length == 2) {
standardUrl = '$standardUrl/files';
standardUri = Uri.parse(standardUrl);
}
Response res = await sourceRequest(
'${standardUri.origin}/${standardUri.pathSegments.sublist(0, 2).join('/')}/rss?path=/',
additionalSettings);
if (res.statusCode == 200) { if (res.statusCode == 200) {
var parsedHtml = parse(res.body); var parsedHtml = parse(res.body);
var allDownloadLinks = var allDownloadLinks = parsedHtml
parsedHtml.querySelectorAll('guid').map((e) => e.innerHtml).toList(); .querySelectorAll('guid')
.map((e) => e.innerHtml)
.where((element) => element.startsWith(standardUrl))
.toList();
getVersion(String url) { getVersion(String url) {
try { try {
var tokens = url.split('/'); var segments = url
var fi = tokens.indexOf('files'); .substring(standardUrl.length)
return tokens[tokens[fi + 2] == 'download' ? fi - 1 : fi + 1]; .split('/')
.where((element) => element.isNotEmpty)
.toList()
.reversed
.toList()
.sublist(1)
.reversed
.toList();
segments = segments.length > 1
? segments.reversed.toList().sublist(1).reversed.toList()
: segments;
var version = segments.isNotEmpty ? segments.join('/') : null;
if (version != null) {
try {
var extractedVersion = extractVersion(
additionalSettings['versionExtractionRegEx'] as String?,
additionalSettings['matchGroupToUse'] as String?,
version);
if (extractedVersion != null) {
version = extractedVersion;
}
} catch (e) {
if (e is NoVersionError) {
version = null;
} else {
rethrow;
}
}
}
return version;
} catch (e) { } catch (e) {
return null; return null;
} }
} }
String? version = getVersion(allDownloadLinks[0]); var apkUrlListAllReleases = allDownloadLinks
.where((element) => element.toLowerCase().endsWith('.apk/download'))
.where((element) => getVersion(element) != null)
.toList();
if (apkUrlListAllReleases.isEmpty) {
throw NoReleasesError();
}
String? version = getVersion(apkUrlListAllReleases[0]);
if (version == null) { if (version == null) {
throw NoVersionError(); throw NoVersionError();
} }
var apkUrlListAllReleases = allDownloadLinks
.where((element) => element.toLowerCase().endsWith('.apk/download'))
.toList();
var apkUrlList = var apkUrlList =
apkUrlListAllReleases // This can be used skipped for fallback support later apkUrlListAllReleases // This can be used skipped for fallback support later
.where((element) => getVersion(element) == version) .where((element) => getVersion(element) == version)
.toList(); .toList();
return APKDetails( var segments = standardUrl.split('/');
version, return APKDetails(version, getApkUrlsFromUrls(apkUrlList),
getApkUrlsFromUrls(apkUrlList), AppNames(name, segments[segments.indexOf('files') - 1]));
AppNames(
name, standardUrl.substring(standardUrl.lastIndexOf('/') + 1)));
} else { } else {
throw getObtainiumHttpError(res); throw getObtainiumHttpError(res);
} }

View File

@@ -1,7 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/custom_app_bar.dart';
import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/components/generated_form_modal.dart';
@@ -62,18 +61,6 @@ class AddAppPageState extends State<AddAppPage> {
var prevHost = pickedSource?.hosts.isNotEmpty == true var prevHost = pickedSource?.hosts.isNotEmpty == true
? pickedSource?.hosts[0] ? pickedSource?.hosts[0]
: null; : null;
try {
var naturalSource =
valid ? sourceProvider.getSource(userInput) : null;
if (naturalSource != null &&
naturalSource.runtimeType.toString() !=
HTML().runtimeType.toString()) {
// If input has changed to match a regular source, reset the override
pickedSourceOverride = null;
}
} catch (e) {
// ignore
}
var source = valid var source = valid
? sourceProvider.getSource(userInput, ? sourceProvider.getSource(userInput,
overrideSource: pickedSourceOverride) overrideSource: pickedSourceOverride)
@@ -163,7 +150,7 @@ class AddAppPageState extends State<AddAppPage> {
app = await sourceProvider.getApp( app = await sourceProvider.getApp(
pickedSource!, userInput.trim(), additionalSettings, pickedSource!, userInput.trim(), additionalSettings,
trackOnlyOverride: trackOnly, trackOnlyOverride: trackOnly,
overrideSource: pickedSourceOverride, sourceIsOverriden: pickedSourceOverride != null,
inferAppIdIfOptional: inferAppIdIfOptional); inferAppIdIfOptional: inferAppIdIfOptional);
// Only download the APK here if you need to for the package ID // Only download the APK here if you need to for the package ID
if (isTempId(app) && app.additionalSettings['trackOnly'] != true) { if (isTempId(app) && app.additionalSettings['trackOnly'] != true) {
@@ -361,8 +348,9 @@ class AddAppPageState extends State<AddAppPage> {
[ [
GeneratedFormDropdown( GeneratedFormDropdown(
'overrideSource', 'overrideSource',
defaultValue: HTML().runtimeType.toString(), defaultValue: '',
[ [
MapEntry('', tr('none')),
...sourceProvider.sources.map( ...sourceProvider.sources.map(
(s) => MapEntry(s.runtimeType.toString(), s.name)) (s) => MapEntry(s.runtimeType.toString(), s.name))
], ],
@@ -577,11 +565,7 @@ class AddAppPageState extends State<AddAppPage> {
const SizedBox( const SizedBox(
height: 16, height: 16,
), ),
if (pickedSourceOverride != null || if (pickedSource != null) getHTMLSourceOverrideDropdown(),
(pickedSource != null &&
pickedSource.runtimeType.toString() ==
HTML().runtimeType.toString()))
getHTMLSourceOverrideDropdown(),
if (shouldShowSearchBar()) getSearchBarRow(), if (shouldShowSearchBar()) getSearchBarRow(),
if (pickedSource != null) if (pickedSource != null)
FutureBuilder( FutureBuilder(

View File

@@ -104,6 +104,10 @@ class _AppPageState extends State<AppPage> {
if (installedVersionIsEstimate) { if (installedVersionIsEstimate) {
infoLines = '${tr('pseudoVersionInUse')}\n$infoLines'; infoLines = '${tr('pseudoVersionInUse')}\n$infoLines';
} }
if ((app?.app.apkUrls.length ?? 0) > 0) {
infoLines =
'$infoLines\n${app?.app.apkUrls.length == 1 ? app?.app.apkUrls[0].key : plural('apk', app?.app.apkUrls.length ?? 0)}';
}
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@@ -1038,7 +1038,7 @@ class AppsPageState extends State<AppsPage> {
IconButton( IconButton(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
style: const ButtonStyle(visualDensity: VisualDensity.compact), style: const ButtonStyle(visualDensity: VisualDensity.compact),
tooltip: isFilterOff ? tr('filter') : tr('filterActive'), tooltip: '${tr('filter')}${isFilterOff ? '' : ' *'}',
onPressed: isFilterOff onPressed: isFilterOff
? showFilterDialog ? showFilterDialog
: () { : () {

View File

@@ -213,7 +213,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
setState(() { setState(() {
importInProgress = true; importInProgress = true;
}); });
if (values['url'] != source.hosts[0]) { if (source.hosts.isEmpty || values['url'] != source.hosts[0]) {
source = sourceProvider.getSource(values['url'], source = sourceProvider.getSource(values['url'],
overrideSource: source.runtimeType.toString()); overrideSource: source.runtimeType.toString());
} }

View File

@@ -167,7 +167,7 @@ String hashListOfLists(List<List<int>> data) {
return hash.hashCode.toString(); return hash.hashCode.toString();
} }
Future<String> checkPartialDownloadHashDynamc(String url, Future<String> checkPartialDownloadHashDynamic(String url,
{int startingSize = 1024, {int startingSize = 1024,
int lowerLimit = 128, int lowerLimit = 128,
Map<String, String>? headers}) async { Map<String, String>? headers}) async {
@@ -532,9 +532,18 @@ class AppsProvider with ChangeNotifier {
{bool needsBGWorkaround = false}) async { {bool needsBGWorkaround = false}) async {
var newInfo = var newInfo =
await pm.getPackageArchiveInfo(archiveFilePath: file.file.path); await pm.getPackageArchiveInfo(archiveFilePath: file.file.path);
if (newInfo == null) {
try {
file.file.deleteSync(recursive: true);
} catch (e) {
//
} finally {
throw ObtainiumError(tr('badDownload'));
}
}
PackageInfo? appInfo = await getInstalledInfo(apps[file.appId]!.app.id); PackageInfo? appInfo = await getInstalledInfo(apps[file.appId]!.app.id);
if (appInfo != null && if (appInfo != null &&
newInfo!.versionCode! < appInfo.versionCode! && newInfo.versionCode! < appInfo.versionCode! &&
!(await canDowngradeApps())) { !(await canDowngradeApps())) {
throw DowngradeError(); throw DowngradeError();
} }
@@ -708,7 +717,7 @@ class AppsProvider with ChangeNotifier {
appsToInstall = appsToInstall =
moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId); moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId);
Future<void> updateFn(String id, {bool skipInstalls = false}) async { Future<String> updateFn(String id, {bool skipInstalls = false}) async {
try { try {
var downloadedArtifact = var downloadedArtifact =
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
@@ -721,8 +730,8 @@ class AppsProvider with ChangeNotifier {
} else { } else {
downloadedDir = downloadedArtifact as DownloadedXApkDir; downloadedDir = downloadedArtifact as DownloadedXApkDir;
} }
var appId = downloadedFile?.appId ?? downloadedDir!.appId; id = downloadedFile?.appId ?? downloadedDir!.appId;
bool willBeSilent = await canInstallSilently(apps[appId]!.app); bool willBeSilent = await canInstallSilently(apps[id]!.app);
switch (settingsProvider.installMethod) { switch (settingsProvider.installMethod) {
case InstallMethodSettings.normal: case InstallMethodSettings.normal:
if (!(await settingsProvider.getInstallPermission( if (!(await settingsProvider.getInstallPermission(
@@ -764,18 +773,19 @@ class AppsProvider with ChangeNotifier {
} }
if (willBeSilent && context == null) { if (willBeSilent && context == null) {
notificationsProvider?.notify(SilentUpdateAttemptNotification( notificationsProvider?.notify(SilentUpdateAttemptNotification(
[apps[appId]!.app], [apps[id]!.app],
id: appId.hashCode)); id: id.hashCode));
} }
installedIds.add(id);
} }
} finally { } finally {
apps[id]?.downloadProgress = null; apps[id]?.downloadProgress = null;
notifyListeners(); notifyListeners();
} }
installedIds.add(id);
} catch (e) { } catch (e) {
errors.add(id, e, appName: apps[id]?.name); errors.add(id, e, appName: apps[id]?.name);
} }
return id;
} }
if (forceParallelDownloads || !settingsProvider.parallelDownloads) { if (forceParallelDownloads || !settingsProvider.parallelDownloads) {
@@ -783,9 +793,9 @@ class AppsProvider with ChangeNotifier {
await updateFn(id); await updateFn(id);
} }
} else { } else {
await Future.wait( List<String> ids = await Future.wait(
appsToInstall.map((id) => updateFn(id, skipInstalls: true))); appsToInstall.map((id) => updateFn(id, skipInstalls: true)));
for (var id in appsToInstall) { for (var id in ids) {
if (!errors.appIdNames.containsKey(id)) { if (!errors.appIdNames.containsKey(id)) {
await updateFn(id); await updateFn(id);
} }

View File

@@ -30,8 +30,22 @@ enum SortOrderSettings { ascending, descending }
const maxAPIRateLimitMinutes = 30; const maxAPIRateLimitMinutes = 30;
const minUpdateIntervalMinutes = maxAPIRateLimitMinutes + 30; const minUpdateIntervalMinutes = maxAPIRateLimitMinutes + 30;
const maxUpdateIntervalMinutes = 4320; const maxUpdateIntervalMinutes = 43200;
List<int> updateIntervals = [15, 30, 60, 120, 180, 360, 720, 1440, 4320, 0] List<int> updateIntervals = [
15,
30,
60,
120,
180,
360,
720,
1440,
4320,
10080,
20160,
43200,
0
]
.where((element) => .where((element) =>
(element >= minUpdateIntervalMinutes && (element >= minUpdateIntervalMinutes &&
element <= maxUpdateIntervalMinutes) || element <= maxUpdateIntervalMinutes) ||

View File

@@ -819,7 +819,7 @@ class SourceProvider {
AppSource source, String url, Map<String, dynamic> additionalSettings, AppSource source, String url, Map<String, dynamic> additionalSettings,
{App? currentApp, {App? currentApp,
bool trackOnlyOverride = false, bool trackOnlyOverride = false,
String? overrideSource, bool sourceIsOverriden = false,
bool inferAppIdIfOptional = false}) async { bool inferAppIdIfOptional = false}) async {
if (trackOnlyOverride || source.enforceTrackOnly) { if (trackOnlyOverride || source.enforceTrackOnly) {
additionalSettings['trackOnly'] = true; additionalSettings['trackOnly'] = true;
@@ -829,8 +829,9 @@ class SourceProvider {
APKDetails apk = APKDetails apk =
await source.getLatestAPKDetails(standardUrl, additionalSettings); await source.getLatestAPKDetails(standardUrl, additionalSettings);
if (source.runtimeType != HTML().runtimeType) { if (source.runtimeType !=
// HTML does it separately HTML().runtimeType && // Some sources do it separately
source.runtimeType != SourceForge().runtimeType) {
String? extractedVersion = extractVersion( String? extractedVersion = extractVersion(
additionalSettings['versionExtractionRegEx'] as String?, additionalSettings['versionExtractionRegEx'] as String?,
additionalSettings['matchGroupToUse'] as String?, additionalSettings['matchGroupToUse'] as String?,
@@ -886,7 +887,9 @@ class SourceProvider {
categories: currentApp?.categories ?? const [], categories: currentApp?.categories ?? const [],
releaseDate: apk.releaseDate, releaseDate: apk.releaseDate,
changeLog: apk.changeLog, changeLog: apk.changeLog,
overrideSource: overrideSource ?? currentApp?.overrideSource, overrideSource: sourceIsOverriden
? source.runtimeType.toString()
: currentApp?.overrideSource,
allowIdChange: currentApp?.allowIdChange ?? allowIdChange: currentApp?.allowIdChange ??
trackOnly || trackOnly ||
(source.appIdInferIsOptional && (source.appIdInferIsOptional &&
@@ -910,6 +913,7 @@ class SourceProvider {
apps.add(await getApp( apps.add(await getApp(
source, source,
url, url,
sourceIsOverriden: sourceOverride != null,
getDefaultValuesFromFormItems( getDefaultValuesFromFormItems(
source.combinedAppSpecificSettingFormItems))); source.combinedAppSpecificSettingFormItems)));
} catch (e) { } catch (e) {

View File

@@ -22,10 +22,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: android_package_manager name: android_package_manager
sha256: e52ca607b9f19f95d5dae4211ed8fa93e67093f22ac570db47489c5bca512940 sha256: "2de859fae7226a7de1c1ff9a2308f1967599408800330501a1ce97927c051153"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" version: "0.7.1"
animations: animations:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -70,10 +70,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: background_fetch name: background_fetch
sha256: "34550cf9b383e5a1844e7d22119aa500508c7df9421fa967c9fb4430d6cb2878" sha256: "1a7868d9bd165eb177f039ff8244cfa7952340b18f7caabf322b26e712b438a3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.2.3"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@@ -150,10 +150,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.3+8" version: "0.3.4+1"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -190,10 +190,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "0042cb3b2a76413ea5f8a2b40cec2a33e01d0c937e91f0f7c211fde4f7739ba6" sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.1" version: "9.1.2"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -206,18 +206,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: dynamic_color name: dynamic_color
sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.6.9" version: "1.7.0"
easy_localization: easy_localization:
dependency: "direct main" dependency: "direct main"
description: description:
name: easy_localization name: easy_localization
sha256: de63e3b422adfc97f256cbb3f8cf12739b6a4993d390f3cadb3f51837afaefe5 sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.5"
easy_logger: easy_logger:
dependency: transitive dependency: transitive
description: description:
@@ -238,10 +238,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
file: file:
dependency: transitive dependency: transitive
description: description:
@@ -336,10 +336,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "30088ce826b5b9cfbf9e8bece34c716c8a59fa54461dcae1e4ac01a94639e762" sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.18+3" version: "0.6.20+1"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
@@ -394,10 +394,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@@ -410,10 +410,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.4" version: "4.1.7"
intl: intl:
dependency: transitive dependency: transitive
description: description:
@@ -438,6 +438,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.1" version: "4.8.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@@ -458,26 +482,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16" version: "0.12.16+1"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.8.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.11.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -506,10 +530,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.3" version: "1.9.0"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -562,26 +586,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: permission_handler name: permission_handler
sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6" sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.2.0" version: "11.3.0"
permission_handler_android: permission_handler_android:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "758284a0976772f9c744d6384fc5dc4834aa61e3f7aa40492927f244767374eb" sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.3" version: "12.0.5"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_apple name: permission_handler_apple
sha256: c6bf440f80acd2a873d3d91a699e4cc770f86e7e6b576dda98759e8b92b39830 sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.3.0" version: "9.4.0"
permission_handler_html: permission_handler_html:
dependency: transitive dependency: transitive
description: description:
@@ -594,10 +618,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_platform_interface name: permission_handler_platform_interface
sha256: "5c43148f2bfb6d14c5a8162c0a712afe891f2d847f35fcff29c406b37da43c3c" sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.0" version: "4.2.0"
permission_handler_windows: permission_handler_windows:
dependency: transitive dependency: transitive
description: description:
@@ -642,18 +666,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: provider name: provider
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.1" version: "6.1.2"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.1" version: "7.2.2"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -706,10 +730,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.3.0"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
@@ -722,10 +746,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_storage name: shared_storage
sha256: "7c65a9d64f0f5521256be974cfd74010af12196657cec9f9fb7b03b2f11bcaf6" sha256: cf20428d06af065311b71e09cbfbbfe431e979a3bf9180001c1952129b7c708f
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.8.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -831,26 +855,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.4" version: "6.2.5"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.2" version: "6.3.0"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.4" version: "6.2.5"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@@ -871,18 +895,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.3.0"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@@ -907,30 +931,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "13.0.0"
web: web:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "0.5.0"
webview_flutter: webview_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
sha256: "71e1bfaef41016c8d5954291df5e9f8c6172f1f6ff3af01b5656456ddb11f94c" sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.4" version: "4.7.0"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: "4ea3c4e1b8ed590162b15b8a61b41b1ef3ff179a314627c16ce40c086d94b8af" sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.14.0" version: "3.15.0"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -943,10 +975,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: b99ca8d8bae9c6b43d568218691aa537fb0aeae1d7d34eadf112a6aa36d26506 sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.11.0" version: "3.12.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@@ -988,5 +1020,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.3 <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.16.6" flutter: ">=3.19.0"

View File

@@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.1+251 # When changing this, update the tag in main() accordingly version: 1.0.4+2254 # When changing this, update the tag in main() accordingly
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'