mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-13 21:36:42 +02:00
Compare commits
89 Commits
v1.0.0
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
ab43856b90 | |||
9dae24ace6 | |||
b6e6568500 | |||
a8eae7f04b | |||
4902e0ef06 | |||
e6926a714f | |||
c9eee4331d | |||
9a8cc2e5c3 | |||
a7c9cd0f27 | |||
efc6846c1c | |||
89edddd38c | |||
e7c2112f41 | |||
d8cd3b6c92 | |||
bb1dd4ecfd | |||
3824b386d7 | |||
a9159fc8a0 | |||
7f4cf6e681 | |||
215f05fbc2 | |||
6d6afe9e69 | |||
66122f1608 | |||
0ad9bbdd8e | |||
59cc08f28a | |||
afc0c3a2fa | |||
a827046acc | |||
fd8f967036 | |||
26be524c6d | |||
8ec3360575 | |||
f66753498b | |||
90e6e5a3a3 | |||
2c4713ff25 | |||
ef3b01ac56 | |||
1cfb258dcc | |||
d13464a392 | |||
f1dd50faee | |||
6f5315db27 | |||
02922c3c8e | |||
03ef649c0f | |||
9083e28637 | |||
cfa4c680cf | |||
a5b3b9d1d0 | |||
13cd7e76c1 | |||
6e7ccfba37 | |||
34fd673e25 | |||
db484f7b28 | |||
b4cf0f5d29 | |||
4db205dd9a | |||
64f8e2a57b | |||
eddc245ff4 | |||
ed2f0f2c0c | |||
7d5a422855 | |||
e420862546 | |||
2cc59948a7 | |||
188d33199e | |||
24928261bb | |||
4c7bda8343 | |||
d88709c999 | |||
29e1481a3b | |||
9d76359543 | |||
f50e791221 | |||
7d08e5225c | |||
3842c1e2df | |||
21b1990991 | |||
e278c9fb5a | |||
bfa29bb7c2 | |||
efa55a9696 | |||
8888cd6264 | |||
34e2c014e3 | |||
5d92a6d013 | |||
fb03b2e95c | |||
5a1e09564c | |||
3783eba401 | |||
a3530ce6bb | |||
27d8655d58 | |||
fb845ce601 | |||
dbd433df9d | |||
badf32ff11 | |||
5e40f3264e | |||
71bb6d9410 | |||
731b682fc9 | |||
c9751227a5 | |||
6ef2a26e94 | |||
5a8efa2388 | |||
d25895fa28 | |||
de09f3ece2 | |||
1135ffb30f | |||
5379cb31e8 | |||
7d41ab44b7 | |||
8dd8f471a2 | |||
657d1cd042 |
2
.flutter
2
.flutter
Submodule .flutter updated: 67457e669f...ba39319843
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -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. -->
|
||||||
|
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -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)**
|
||||||
|
@ -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
|
||||||
|
@ -108,3 +108,16 @@ dependencies {
|
|||||||
|
|
||||||
implementation "com.github.topjohnwu.libsu:core:5.2.2"
|
implementation "com.github.topjohnwu.libsu:core:5.2.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
|
||||||
|
import com.android.build.OutputFile
|
||||||
|
android.applicationVariants.all { variant ->
|
||||||
|
variant.outputs.each { output ->
|
||||||
|
def abiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
|
||||||
|
if (abiVersionCode != null) {
|
||||||
|
output.versionCodeOverride = variant.versionCode * 10 + abiVersionCode
|
||||||
|
} else {
|
||||||
|
output.versionCodeOverride = variant.versionCode * 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Ne prikazuj upozorenja „Samo za praćenje”",
|
"dontShowTrackOnlyWarnings": "Ne prikazuj upozorenja „Samo za praćenje”",
|
||||||
"dontShowAPKOriginWarnings": "Ne prikazuj upozorenja o porijeklu APK-a",
|
"dontShowAPKOriginWarnings": "Ne prikazuj upozorenja o porijeklu APK-a",
|
||||||
"moveNonInstalledAppsToBottom": "Premjesti neinstalirane aplikacije na dno prikaza aplikacija",
|
"moveNonInstalledAppsToBottom": "Premjesti neinstalirane aplikacije na dno prikaza aplikacija",
|
||||||
"gitlabPATLabel": "GitLab token za lični pristup\n(Omogućava pretraživanje i bolje otkrivanje APK-a)",
|
"gitlabPATLabel": "GitLab token za lični pristup",
|
||||||
"about": "O nama",
|
"about": "O nama",
|
||||||
"requiresCredentialsInSettings": "{}: Za ovo su potrebni dodatni akreditivi (u Postavkama)",
|
"requiresCredentialsInSettings": "{}: Za ovo su potrebni dodatni akreditivi (u Postavkama)",
|
||||||
"checkOnStart": "Provjerite ima li novosti pri pokretanju",
|
"checkOnStart": "Provjerite ima li novosti pri pokretanju",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Dodajte ove informacije ispod.",
|
"addInfoBelow": "Dodajte ove informacije ispod.",
|
||||||
"addInfoInSettings": "Dodajte ove informacije u Postavkama.",
|
"addInfoInSettings": "Dodajte ove informacije u Postavkama.",
|
||||||
"githubSourceNote": "GitHub ograničavanje se može izbjeći korišćenjem tokena za lični pristup.",
|
"githubSourceNote": "GitHub ograničavanje se može izbjeći korišćenjem tokena za lični pristup.",
|
||||||
"gitlabSourceNote": "GitLab APK preuzimanje možda neće raditi bez tokena za lični pristup.",
|
|
||||||
"sortByLastLinkSegment": "Sortiraj samo po zadnjem segmentu veze",
|
"sortByLastLinkSegment": "Sortiraj samo po zadnjem segmentu veze",
|
||||||
"filterReleaseNotesByRegEx": "Filtirajte promjene u izdanju po regularnom izrazu",
|
"filterReleaseNotesByRegEx": "Filtirajte promjene u izdanju po regularnom izrazu",
|
||||||
"customLinkFilterRegex": "Prilagođeni APK link filtrira se po regularnom izrazu (Zadano '.apk$')",
|
"customLinkFilterRegex": "Prilagođeni APK link filtrira se po regularnom izrazu (Zadano '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Instalirano",
|
"installed": "Instalirano",
|
||||||
"latest": "Najnoviji",
|
"latest": "Najnoviji",
|
||||||
"invertRegEx": "Obrni regularni izraz",
|
"invertRegEx": "Obrni regularni izraz",
|
||||||
|
"note": "Note",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Nezobrazovat varování pro 'Jen sledované'",
|
"dontShowTrackOnlyWarnings": "Nezobrazovat varování pro 'Jen sledované'",
|
||||||
"dontShowAPKOriginWarnings": "Nezobrazovat varování pro původ APK",
|
"dontShowAPKOriginWarnings": "Nezobrazovat varování pro původ APK",
|
||||||
"moveNonInstalledAppsToBottom": "Přesunout nenainstalované aplikace na konec zobrazení Aplikace",
|
"moveNonInstalledAppsToBottom": "Přesunout nenainstalované aplikace na konec zobrazení Aplikace",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Umožňuje vyhledávání a lepší zjišťování APK)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "O",
|
"about": "O",
|
||||||
"requiresCredentialsInSettings": "{}: Vyžaduje další pověření (v nastavení)",
|
"requiresCredentialsInSettings": "{}: Vyžaduje další pověření (v nastavení)",
|
||||||
"checkOnStart": "Zkontrolovat jednou při spuštění",
|
"checkOnStart": "Zkontrolovat jednou při spuštění",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Přidat tuto informaci na konec stránky.",
|
"addInfoBelow": "Přidat tuto informaci na konec stránky.",
|
||||||
"addInfoInSettings": "Přidat tuto informaci do nastavení.",
|
"addInfoInSettings": "Přidat tuto informaci do nastavení.",
|
||||||
"githubSourceNote": "Omezení rychlosti GitHub lze obejít pomocí klíče API.",
|
"githubSourceNote": "Omezení rychlosti GitHub lze obejít pomocí klíče API.",
|
||||||
"gitlabSourceNote": "Extrakce GitLab APK nemusí fungovat bez klíče API",
|
|
||||||
"sortByLastLinkSegment": "Seřadit pouze podle poslední části odkazu",
|
"sortByLastLinkSegment": "Seřadit pouze podle poslední části odkazu",
|
||||||
"filterReleaseNotesByRegEx": "Filtrovat poznámky k vydání podle regulárního výrazu",
|
"filterReleaseNotesByRegEx": "Filtrovat poznámky k vydání podle regulárního výrazu",
|
||||||
"customLinkFilterRegex": "Vlastní filtr odkazů APK podle regulárního výrazu (výchozí '.apk$')",
|
"customLinkFilterRegex": "Vlastní filtr odkazů APK podle regulárního výrazu (výchozí '.apk$')",
|
||||||
@ -292,12 +290,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": "Poznámka",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,26 +218,25 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen",
|
"dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen",
|
||||||
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
|
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
|
||||||
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche und bessere APK Entdeckung)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "Über",
|
"about": "Über",
|
||||||
"requiresCredentialsInSettings": "{}: Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
"requiresCredentialsInSettings": "{}: Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
||||||
"checkOnStart": "Überprüfe einmalig beim Start",
|
"checkOnStart": "Überprüfe einmalig beim Start",
|
||||||
"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",
|
||||||
"addInfoBelow": "Fügen Sie diese Informationen unten hinzu.",
|
"addInfoBelow": "Fügen Sie diese Informationen unten hinzu.",
|
||||||
"addInfoInSettings": "Fügen Sie diese Info in den Einstellungen hinzu.",
|
"addInfoInSettings": "Fügen Sie diese Info in den Einstellungen hinzu.",
|
||||||
"githubSourceNote": "Die GitHub-Ratenbegrenzung kann mit einem API-Schlüssel umgangen werden.",
|
"githubSourceNote": "Die GitHub-Ratenbegrenzung kann mit einem API-Schlüssel umgangen werden.",
|
||||||
"gitlabSourceNote": "GitLab APK-Extraktion funktioniert möglicherweise nicht ohne API-Schlüssel",
|
|
||||||
"sortByLastLinkSegment": "Sortiere nur nach dem letzten Teil des Links",
|
"sortByLastLinkSegment": "Sortiere nur nach dem letzten Teil des Links",
|
||||||
"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 +266,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,10 +292,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(r)",
|
"latest": "Neueste Version",
|
||||||
"invertRegEx": "Regulären Ausdruck invertieren",
|
"invertRegEx": "Regulären Ausdruck invertieren",
|
||||||
|
"note": "Hinweis",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Don't show 'Track-Only' warnings",
|
"dontShowTrackOnlyWarnings": "Don't show 'Track-Only' warnings",
|
||||||
"dontShowAPKOriginWarnings": "Don't show APK origin warnings",
|
"dontShowAPKOriginWarnings": "Don't show APK origin warnings",
|
||||||
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "{} needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{} needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check for updates on startup",
|
"checkOnStart": "Check for updates on startup",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Add this info below.",
|
"addInfoBelow": "Add this info below.",
|
||||||
"addInfoInSettings": "Add this info in the Settings.",
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
|
||||||
"sortByLastLinkSegment": "Sort by only the last segment of the link",
|
"sortByLastLinkSegment": "Sort by only the last segment of the link",
|
||||||
"filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression",
|
"filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression",
|
||||||
"customLinkFilterRegex": "Custom APK Link Filter by Regular Expression (Default '.apk$')",
|
"customLinkFilterRegex": "Custom APK Link Filter by Regular Expression (Default '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Installed",
|
"installed": "Installed",
|
||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"invertRegEx": "Invert regular expression",
|
"invertRegEx": "Invert regular expression",
|
||||||
|
"note": "Note",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps en 'solo seguimiento'",
|
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps en 'solo seguimiento'",
|
||||||
"dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs",
|
"dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs",
|
||||||
"moveNonInstalledAppsToBottom": "Mover Apps no instaladas al final",
|
"moveNonInstalledAppsToBottom": "Mover Apps no instaladas al final",
|
||||||
"gitlabPATLabel": "Token de acceso personal a GitLab\n(habilita la búsqueda y mejor detección de APKs)",
|
"gitlabPATLabel": "Token de acceso personal a GitLab",
|
||||||
"about": "Acerca",
|
"about": "Acerca",
|
||||||
"requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)",
|
"requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)",
|
||||||
"checkOnStart": "Comprobar actualizaciones al inicio",
|
"checkOnStart": "Comprobar actualizaciones al inicio",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Añadir esta información debajo.",
|
"addInfoBelow": "Añadir esta información debajo.",
|
||||||
"addInfoInSettings": "Puede añadir esta información en Ajustes.",
|
"addInfoInSettings": "Puede añadir esta información en Ajustes.",
|
||||||
"githubSourceNote": "La limitación de velocidad de GitHub puede evitarse con un 'token de acceso personal'.",
|
"githubSourceNote": "La limitación de velocidad de GitHub puede evitarse con un 'token de acceso personal'.",
|
||||||
"gitlabSourceNote": "La extracción de APK de GitLab podría no funcionar sin un 'token de acceso personal'.",
|
|
||||||
"sortByLastLinkSegment": "Ordenar sólo por el último segmento del enlace",
|
"sortByLastLinkSegment": "Ordenar sólo por el último segmento del enlace",
|
||||||
"filterReleaseNotesByRegEx": "Filtrar por notas de versión (release notes)",
|
"filterReleaseNotesByRegEx": "Filtrar por notas de versión (release notes)",
|
||||||
"customLinkFilterRegex": "Filtro personalizado de enlace APK (por defecto '.apk$')",
|
"customLinkFilterRegex": "Filtro personalizado de enlace APK (por defecto '.apk$')",
|
||||||
@ -298,6 +296,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": "Nota",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@
|
|||||||
"removeOutdatedFilter": "فیلتر برنامه قدیمی را حذف کنید",
|
"removeOutdatedFilter": "فیلتر برنامه قدیمی را حذف کنید",
|
||||||
"showOutdatedOnly": "فقط برنامه های قدیمی را نشان دهید",
|
"showOutdatedOnly": "فقط برنامه های قدیمی را نشان دهید",
|
||||||
"filter": "فیلتر",
|
"filter": "فیلتر",
|
||||||
"filterActive": "فیلتر *",
|
|
||||||
"filterApps": "فیلتر کردن برنامه ها",
|
"filterApps": "فیلتر کردن برنامه ها",
|
||||||
"appName": "نام برنامه",
|
"appName": "نام برنامه",
|
||||||
"author": "سازنده",
|
"author": "سازنده",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید",
|
"dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید",
|
||||||
"dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید",
|
"dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید",
|
||||||
"moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید",
|
"moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید",
|
||||||
"gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو و کشف بهتر APK را فعال میکند)",
|
"gitlabPATLabel": "رمز دسترسی شخصی GitLab",
|
||||||
"about": "درباره",
|
"about": "درباره",
|
||||||
"requiresCredentialsInSettings": "{}: این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)",
|
"requiresCredentialsInSettings": "{}: این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)",
|
||||||
"checkOnStart": "بررسی در شروع",
|
"checkOnStart": "بررسی در شروع",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "این اطلاعات را در زیر اضافه کنید",
|
"addInfoBelow": "این اطلاعات را در زیر اضافه کنید",
|
||||||
"addInfoInSettings": "این اطلاعات را در تنظیمات اضافه کنید.",
|
"addInfoInSettings": "این اطلاعات را در تنظیمات اضافه کنید.",
|
||||||
"githubSourceNote": "با استفاده از کلید API می توان از محدودیت نرخ GitHub جلوگیری کرد.",
|
"githubSourceNote": "با استفاده از کلید API می توان از محدودیت نرخ GitHub جلوگیری کرد.",
|
||||||
"gitlabSourceNote": "استخراج APK GitLab ممکن است بدون کلید API کار نکند.",
|
|
||||||
"sortByLastLinkSegment": "فقط بر اساس آخرین بخش پیوند مرتب کنید",
|
"sortByLastLinkSegment": "فقط بر اساس آخرین بخش پیوند مرتب کنید",
|
||||||
"filterReleaseNotesByRegEx": "یادداشت های انتشار را با بیان منظم فیلتر کنید",
|
"filterReleaseNotesByRegEx": "یادداشت های انتشار را با بیان منظم فیلتر کنید",
|
||||||
"customLinkFilterRegex": "فیلتر پیوند سفارشی بر اساس عبارت منظم (پیشفرض '.apk$')",
|
"customLinkFilterRegex": "فیلتر پیوند سفارشی بر اساس عبارت منظم (پیشفرض '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "نصب شده است",
|
"installed": "نصب شده است",
|
||||||
"latest": "آخرین",
|
"latest": "آخرین",
|
||||||
"invertRegEx": "معکوس کردن عبارت منظم",
|
"invertRegEx": "معکوس کردن عبارت منظم",
|
||||||
|
"note": "Note",
|
||||||
|
"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": "برنامه ها حذف شوند؟"
|
||||||
@ -349,5 +350,9 @@
|
|||||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",
|
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",
|
||||||
"other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند."
|
"other": "ممکن است {} و {} برنامه های دیگر به روز شده باشند."
|
||||||
|
},
|
||||||
|
"apk": {
|
||||||
|
"one": "{} APK",
|
||||||
|
"other": "{} APKs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -168,7 +167,7 @@
|
|||||||
"lastUpdateCheckX": "Vérification de la dernière mise à jour : {}",
|
"lastUpdateCheckX": "Vérification de la dernière mise à jour : {}",
|
||||||
"remove": "Retirer",
|
"remove": "Retirer",
|
||||||
"yesMarkUpdated": "Oui, marquer comme mis à jour",
|
"yesMarkUpdated": "Oui, marquer comme mis à jour",
|
||||||
"fdroid": "F-Droïde Officiel",
|
"fdroid": "F-Droid Officiel",
|
||||||
"appIdOrName": "ID ou nom de l'application",
|
"appIdOrName": "ID ou nom de l'application",
|
||||||
"appId": "ID de l'application",
|
"appId": "ID de l'application",
|
||||||
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
|
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
|
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
|
||||||
"dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK",
|
"dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK",
|
||||||
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
|
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
|
||||||
"gitlabPATLabel": "Jeton d'accès personnel GitLab\\n (permet la recherche et une meilleure découverte d'APK)",
|
"gitlabPATLabel": "Jeton d'accès personnel GitLab",
|
||||||
"about": "À propos de",
|
"about": "À propos de",
|
||||||
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Vérifier les mises à jour au démarrage",
|
"checkOnStart": "Vérifier les mises à jour au démarrage",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Ajoutez ces informations ci-dessous.",
|
"addInfoBelow": "Ajoutez ces informations ci-dessous.",
|
||||||
"addInfoInSettings": "Ajoutez ces informations dans les paramètres.",
|
"addInfoInSettings": "Ajoutez ces informations dans les paramètres.",
|
||||||
"githubSourceNote": "La limitation du débit GitHub peut être évitée à l'aide d'une clé API.",
|
"githubSourceNote": "La limitation du débit GitHub peut être évitée à l'aide d'une clé API.",
|
||||||
"gitlabSourceNote": "L'extraction d'APK GitLab peut ne pas fonctionner sans clé API.",
|
|
||||||
"sortByLastLinkSegment": "Trier uniquement sur le dernier segment du lien",
|
"sortByLastLinkSegment": "Trier uniquement sur le dernier segment du lien",
|
||||||
"filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière",
|
"filterReleaseNotesByRegEx": "Filtrer les notes de version par expression régulière",
|
||||||
"customLinkFilterRegex": "Filtre de lien APK personnalisé par expression régulière (par défaut '.apk$')",
|
"customLinkFilterRegex": "Filtre de lien APK personnalisé par expression régulière (par défaut '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Installée",
|
"installed": "Installée",
|
||||||
"latest": "Dernier",
|
"latest": "Dernier",
|
||||||
"invertRegEx": "Inverser l'expression régulière",
|
"invertRegEx": "Inverser l'expression régulière",
|
||||||
|
"note": "Note",
|
||||||
|
"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 ?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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ő",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést",
|
"dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést",
|
||||||
"dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket",
|
"dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket",
|
||||||
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést és jobb APK felfedezés)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "Rólunk",
|
"about": "Rólunk",
|
||||||
"requiresCredentialsInSettings": "{}: Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
"requiresCredentialsInSettings": "{}: Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
||||||
"checkOnStart": "Egyszer az alkalmazás indításakor is",
|
"checkOnStart": "Egyszer az alkalmazás indításakor is",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Adja hozzá ezt az infót alább.",
|
"addInfoBelow": "Adja hozzá ezt az infót alább.",
|
||||||
"addInfoInSettings": "Adja hozzá ezt az infót a Beállításokban.",
|
"addInfoInSettings": "Adja hozzá ezt az infót a Beállításokban.",
|
||||||
"githubSourceNote": "A GitHub sebességkorlátozás elkerülhető API-kulcs használatával.",
|
"githubSourceNote": "A GitHub sebességkorlátozás elkerülhető API-kulcs használatával.",
|
||||||
"gitlabSourceNote": "Előfordulhat, hogy a GitLab APK kibontása nem működik API-kulcs nélkül.",
|
|
||||||
"sortByLastLinkSegment": "Rendezés csak a link utolsó szegmense szerint",
|
"sortByLastLinkSegment": "Rendezés csak a link utolsó szegmense szerint",
|
||||||
"filterReleaseNotesByRegEx": "Kiadási megjegyzések szűrése reguláris kifejezéssel",
|
"filterReleaseNotesByRegEx": "Kiadási megjegyzések szűrése reguláris kifejezéssel",
|
||||||
"customLinkFilterRegex": "Egyéni APK hivatkozásszűrő reguláris kifejezéssel (Alapérték '.apk$')",
|
"customLinkFilterRegex": "Egyéni APK hivatkozásszűrő reguláris kifejezéssel (Alapérték '.apk$')",
|
||||||
@ -283,14 +281,14 @@
|
|||||||
"parallelDownloads": "Párhuzamos letöltéseket enged",
|
"parallelDownloads": "Párhuzamos letöltéseket enged",
|
||||||
"installMethod": "Telepítési mód",
|
"installMethod": "Telepítési mód",
|
||||||
"normal": "Normál",
|
"normal": "Normál",
|
||||||
"root": "Gyökér",
|
"root": "Root",
|
||||||
"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 álverziós módszer",
|
||||||
"partialAPKHash": "Részleges APK Hash",
|
"partialAPKHash": "Részleges APK Hash",
|
||||||
"APKLinkHash": "APK Link Hash",
|
"APKLinkHash": "APK Link Hash",
|
||||||
"directAPKLink": "Közvetlen APK Link",
|
"directAPKLink": "Közvetlen APK Link",
|
||||||
@ -298,9 +296,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": "Megjegyzés:",
|
||||||
|
"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",
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Non mostrare gli avvisi 'Solo-Monitoraggio'",
|
"dontShowTrackOnlyWarnings": "Non mostrare gli avvisi 'Solo-Monitoraggio'",
|
||||||
"dontShowAPKOriginWarnings": "Non mostrare gli avvisi di origine dell'APK",
|
"dontShowAPKOriginWarnings": "Non mostrare gli avvisi di origine dell'APK",
|
||||||
"moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista",
|
"moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(attiva la ricerca e migliora la rilevazione di apk)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "Informazioni",
|
"about": "Informazioni",
|
||||||
"requiresCredentialsInSettings": "{}: Servono credenziali aggiuntive (in Impostazioni)",
|
"requiresCredentialsInSettings": "{}: Servono credenziali aggiuntive (in Impostazioni)",
|
||||||
"checkOnStart": "Controlla una volta all'avvio",
|
"checkOnStart": "Controlla una volta all'avvio",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Aggiungi questa info sotto.",
|
"addInfoBelow": "Aggiungi questa info sotto.",
|
||||||
"addInfoInSettings": "Aggiungi questa info nelle impostazioni.",
|
"addInfoInSettings": "Aggiungi questa info nelle impostazioni.",
|
||||||
"githubSourceNote": "Il limite di ricerca GitHub può essere evitato usando una chiave API.",
|
"githubSourceNote": "Il limite di ricerca GitHub può essere evitato usando una chiave API.",
|
||||||
"gitlabSourceNote": "L'estrazione di APK da GitLab potrebbe non funzionare senza chiave API.",
|
|
||||||
"sortByLastLinkSegment": "Ordina solo in base all'ultimo segmento del collegamento",
|
"sortByLastLinkSegment": "Ordina solo in base all'ultimo segmento del collegamento",
|
||||||
"filterReleaseNotesByRegEx": "Filtra le note di rilascio con espressione regolare",
|
"filterReleaseNotesByRegEx": "Filtra le note di rilascio con espressione regolare",
|
||||||
"customLinkFilterRegex": "Filtra link APK personalizzato con espressione regolare (predefinito '.apk$')",
|
"customLinkFilterRegex": "Filtra link APK personalizzato con espressione regolare (predefinito '.apk$')",
|
||||||
@ -283,13 +281,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,6 +296,9 @@
|
|||||||
"installed": "Installato",
|
"installed": "Installato",
|
||||||
"latest": "Ultimo",
|
"latest": "Ultimo",
|
||||||
"invertRegEx": "Inverti espressione regolare",
|
"invertRegEx": "Inverti espressione regolare",
|
||||||
|
"note": "Nota",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@
|
|||||||
"removeOutdatedFilter": "アップデートが存在するアプリのフィルターを解除",
|
"removeOutdatedFilter": "アップデートが存在するアプリのフィルターを解除",
|
||||||
"showOutdatedOnly": "アップデートが存在するアプリのみ表示する",
|
"showOutdatedOnly": "アップデートが存在するアプリのみ表示する",
|
||||||
"filter": "フィルター",
|
"filter": "フィルター",
|
||||||
"filterActive": "フィルター *",
|
|
||||||
"filterApps": "アプリをフィルタリングする",
|
"filterApps": "アプリをフィルタリングする",
|
||||||
"appName": "アプリ名",
|
"appName": "アプリ名",
|
||||||
"author": "作者",
|
"author": "作者",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない",
|
"dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない",
|
||||||
"dontShowAPKOriginWarnings": "APKのダウンロード元の警告を表示しない",
|
"dontShowAPKOriginWarnings": "APKのダウンロード元の警告を表示しない",
|
||||||
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
||||||
"gitlabPATLabel": "GitLab パーソナルアクセストークン\n(検索とより良いAPK検出の有効化)",
|
"gitlabPATLabel": "GitLab パーソナルアクセストークン",
|
||||||
"about": "概要",
|
"about": "概要",
|
||||||
"requiresCredentialsInSettings": "{}: これには追加の認証が必要です (設定にて)",
|
"requiresCredentialsInSettings": "{}: これには追加の認証が必要です (設定にて)",
|
||||||
"checkOnStart": "起動時にアップデートを確認する",
|
"checkOnStart": "起動時にアップデートを確認する",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "下部でこの情報を追加してください。",
|
"addInfoBelow": "下部でこの情報を追加してください。",
|
||||||
"addInfoInSettings": "設定でこの情報を追加してください。",
|
"addInfoInSettings": "設定でこの情報を追加してください。",
|
||||||
"githubSourceNote": "GitHubのレート制限はAPIキーを使うことで回避できます。",
|
"githubSourceNote": "GitHubのレート制限はAPIキーを使うことで回避できます。",
|
||||||
"gitlabSourceNote": "GitLabのAPK抽出はAPIキーがないと動作しない場合があります。",
|
|
||||||
"sortByLastLinkSegment": "リンクの最後のセグメントのみでソートする",
|
"sortByLastLinkSegment": "リンクの最後のセグメントのみでソートする",
|
||||||
"filterReleaseNotesByRegEx": "正規表現でリリースノートをフィルタリングする",
|
"filterReleaseNotesByRegEx": "正規表現でリリースノートをフィルタリングする",
|
||||||
"customLinkFilterRegex": "正規表現によるカスタムリンクフィルター (デフォルト '.apk$')",
|
"customLinkFilterRegex": "正規表現によるカスタムリンクフィルター (デフォルト '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "インストール済み",
|
"installed": "インストール済み",
|
||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"invertRegEx": "正規表現を反転",
|
"invertRegEx": "正規表現を反転",
|
||||||
|
"note": "注",
|
||||||
|
"selfHostedNote": "ドロップダウン\"{}\"を使用すると、あらゆるソースのセルフホスト/カスタムインスタンスにアクセスできます。",
|
||||||
|
"badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
@ -349,5 +350,9 @@
|
|||||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
|
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
|
||||||
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
|
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
|
||||||
|
},
|
||||||
|
"apk": {
|
||||||
|
"one": "{}APK",
|
||||||
|
"other": "{}APK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven",
|
"dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven",
|
||||||
"dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven",
|
"dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven",
|
||||||
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
|
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\n(Maakt het mogelijk beter te zoeken naar APK's)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "Over",
|
"about": "Over",
|
||||||
"requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)",
|
"requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)",
|
||||||
"checkOnStart": "Controleren op updates bij opstarten",
|
"checkOnStart": "Controleren op updates bij opstarten",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Voeg deze informatie hieronder toe.",
|
"addInfoBelow": "Voeg deze informatie hieronder toe.",
|
||||||
"addInfoInSettings": "Voeg deze informatie toe in de instellingen.",
|
"addInfoInSettings": "Voeg deze informatie toe in de instellingen.",
|
||||||
"githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.",
|
"githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.",
|
||||||
"gitlabSourceNote": "GitLab APK-extractie werkt mogelijk niet zonder een API-sleutel.",
|
|
||||||
"sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link",
|
"sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link",
|
||||||
"filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.",
|
"filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.",
|
||||||
"customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').",
|
"customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Geïnstalleerd",
|
"installed": "Geïnstalleerd",
|
||||||
"latest": "Laatste",
|
"latest": "Laatste",
|
||||||
"invertRegEx": "Reguliere expressie omkeren",
|
"invertRegEx": "Reguliere expressie omkeren",
|
||||||
|
"note": "Opmerking",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Nie pokazuj ostrzeżeń \"Tylko obserwowana\"",
|
"dontShowTrackOnlyWarnings": "Nie pokazuj ostrzeżeń \"Tylko obserwowana\"",
|
||||||
"dontShowAPKOriginWarnings": "Nie pokazuj ostrzeżeń o pochodzeniu APK",
|
"dontShowAPKOriginWarnings": "Nie pokazuj ostrzeżeń o pochodzeniu APK",
|
||||||
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
||||||
"gitlabPATLabel": "Osobisty token dostępu GitLab\n(Umożliwia wyszukiwanie i lepsze wykrywanie APK)",
|
"gitlabPATLabel": "Osobisty token dostępu GitLab",
|
||||||
"about": "Więcej informacji",
|
"about": "Więcej informacji",
|
||||||
"requiresCredentialsInSettings": "{}: Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
"requiresCredentialsInSettings": "{}: Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
||||||
"checkOnStart": "Sprawdź aktualizacje przy uruchomieniu",
|
"checkOnStart": "Sprawdź aktualizacje przy uruchomieniu",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Dodaj tę informację poniżej.",
|
"addInfoBelow": "Dodaj tę informację poniżej.",
|
||||||
"addInfoInSettings": "Dodaj tę informację w Ustawieniach.",
|
"addInfoInSettings": "Dodaj tę informację w Ustawieniach.",
|
||||||
"githubSourceNote": "Limit żądań GitHub można ominąć za pomocą klucza API.",
|
"githubSourceNote": "Limit żądań GitHub można ominąć za pomocą klucza API.",
|
||||||
"gitlabSourceNote": "Pozyskiwanie pliku APK z GitLab może nie działać bez klucza API.",
|
|
||||||
"sortByLastLinkSegment": "Sortuj tylko według ostatniego segmentu łącza",
|
"sortByLastLinkSegment": "Sortuj tylko według ostatniego segmentu łącza",
|
||||||
"filterReleaseNotesByRegEx": "Filtruj informacje o wersji według wyrażenia regularnego",
|
"filterReleaseNotesByRegEx": "Filtruj informacje o wersji według wyrażenia regularnego",
|
||||||
"customLinkFilterRegex": "Filtruj linki APK według wyrażenia regularnego (domyślnie \".apk$\")",
|
"customLinkFilterRegex": "Filtruj linki APK według wyrażenia regularnego (domyślnie \".apk$\")",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Zainstalowano",
|
"installed": "Zainstalowano",
|
||||||
"latest": "Najnowszy",
|
"latest": "Najnowszy",
|
||||||
"invertRegEx": "Odwróć wyrażenie regularne",
|
"invertRegEx": "Odwróć wyrażenie regularne",
|
||||||
|
"note": "Uwaga",
|
||||||
|
"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?",
|
||||||
@ -375,5 +376,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"invalidURLForSource": "URL {} inválida",
|
"invalidURLForSource": "URL {} inválida",
|
||||||
"noReleaseFound": "Não foi possível encontrar uma versão adequada",
|
"noReleaseFound": "Não foi possível encontrar uma versão adequada",
|
||||||
"noVersionFound": "Não foi possível encontrar uma versão",
|
"noVersionFound": "Não foi possível encontrar uma versão",
|
||||||
"urlMatchesNoSource": "URL não corresponde a uma fonte conhecida",
|
"urlMatchesNoSource": "A URL não corresponde a uma fonte conhecida",
|
||||||
"cantInstallOlderVersion": "Não é permitido instalar uma versão anterior de um aplicativo",
|
"cantInstallOlderVersion": "Não é permitido instalar uma versão anterior de um aplicativo",
|
||||||
"appIdMismatch": "ID do pacote baixado não é igual ao ID do aplicativo instalado",
|
"appIdMismatch": "ID do pacote baixado não é igual ao ID do aplicativo instalado",
|
||||||
"functionNotImplemented": "Esta classe não implementou essa função",
|
"functionNotImplemented": "Esta classe não implementou essa função",
|
||||||
@ -11,10 +11,10 @@
|
|||||||
"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 por expressão regular",
|
"filterReleaseTitlesByRegEx": "Filtrar títulos de versões usando expressão regular",
|
||||||
"invalidRegEx": "Expressão regular inválida",
|
"invalidRegEx": "Expressão regular inválida",
|
||||||
"noDescription": "Sem descrição",
|
"noDescription": "Sem descrição",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"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": "Favoritados 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 monitorar'",
|
"xIsTrackOnly": "{} é 'Apenas monitorar'",
|
||||||
@ -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 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",
|
||||||
@ -70,34 +70,33 @@
|
|||||||
"markSelectedAppsUpdated": "Marcar aplicativos selecionados como Atualizados",
|
"markSelectedAppsUpdated": "Marcar aplicativos selecionados como Atualizados",
|
||||||
"pinToTop": "Fixar no topo",
|
"pinToTop": "Fixar no topo",
|
||||||
"unpinFromTop": "Desafixar do topo",
|
"unpinFromTop": "Desafixar do topo",
|
||||||
"resetInstallStatusForSelectedAppsQuestion": "Reiniciar status de instalação para aplicativos selecionados?",
|
"resetInstallStatusForSelectedAppsQuestion": "Reiniciar status de instalação nos aplicativos selecionados?",
|
||||||
"installStatusOfXWillBeResetExplanation": "O status de instalação de qualquer aplicativo selecionado será reiniciado.\n\nIsso pode ajudar quando uma versão de um aplicativo mostrada no Obtainium é incorreta devido a falhas ao atualizar ou outros problemas.",
|
"installStatusOfXWillBeResetExplanation": "O status de instalação de todos os aplicativos selecionados será reiniciado.\n\nIsso pode ajudar quando uma versão de um aplicativo mostrada no Obtainium é incorreta devido a falhas ao atualizar ou outros problemas.",
|
||||||
"customLinkMessage": "Esses links funcionam em dispositivos com o Obtainium instalado",
|
"customLinkMessage": "Esses links funcionam em dispositivos com o Obtainium instalado",
|
||||||
"shareAppConfigLinks": "Compartilhar configuração do aplicativo como link HTML",
|
"shareAppConfigLinks": "Compartilhar configuração do aplicativo como link HTML",
|
||||||
"shareSelectedAppURLs": "Compartilhar URLs de aplicativos selecionados",
|
"shareSelectedAppURLs": "Compartilhar URLs de aplicativos selecionados",
|
||||||
"resetInstallStatus": "Reiniciar status de Iistalação",
|
"resetInstallStatus": "Reiniciar status de instalação",
|
||||||
"more": "Mais",
|
"more": "Mais",
|
||||||
"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",
|
||||||
"upToDateApps": "Aplicativos tualizados",
|
"upToDateApps": "Aplicativos atualizados",
|
||||||
"nonInstalledApps": "Aplicativos não instalados",
|
"nonInstalledApps": "Aplicativos não instalados",
|
||||||
"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": "Input Inválido",
|
"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 internet 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",
|
||||||
@ -151,7 +150,7 @@
|
|||||||
"appsRemoved": "Aplicativos removidos",
|
"appsRemoved": "Aplicativos removidos",
|
||||||
"appsRemovedNotifDescription": "Notifica o usuário quando um ou mais aplicativos foram removidos devido a erros de carregamento",
|
"appsRemovedNotifDescription": "Notifica o usuário quando um ou mais aplicativos foram removidos devido a erros de carregamento",
|
||||||
"xWasRemovedDueToErrorY": "{} foi removido devido a este erro: {}",
|
"xWasRemovedDueToErrorY": "{} foi removido devido a este erro: {}",
|
||||||
"completeAppInstallation": "Instalação do aplicativo completa",
|
"completeAppInstallation": "Instalação do aplicativo concluída",
|
||||||
"obtainiumMustBeOpenToInstallApps": "Obtainium deve estar aberto para instalar os aplicativos",
|
"obtainiumMustBeOpenToInstallApps": "Obtainium deve estar aberto para instalar os aplicativos",
|
||||||
"completeAppInstallationNotifDescription": "Pede ao usuário que retorne ao Obtainium para finalizar a instalação de um aplicativo",
|
"completeAppInstallationNotifDescription": "Pede ao usuário que retorne ao Obtainium para finalizar a instalação de um aplicativo",
|
||||||
"checkingForUpdates": "Verificando atualizações",
|
"checkingForUpdates": "Verificando atualizações",
|
||||||
@ -167,15 +166,15 @@
|
|||||||
"installedVersionX": "Versão instalada: {}",
|
"installedVersionX": "Versão instalada: {}",
|
||||||
"lastUpdateCheckX": "Última verificação de atualizações: {}",
|
"lastUpdateCheckX": "Última verificação de atualizações: {}",
|
||||||
"remove": "Remover",
|
"remove": "Remover",
|
||||||
"yesMarkUpdated": "Sim, marcar como Atualizado",
|
"yesMarkUpdated": "Sim, marcar como atualizado",
|
||||||
"fdroid": "Oficial F-Droid",
|
"fdroid": "Oficial F-Droid",
|
||||||
"appIdOrName": "ID do aplicativo ou nome",
|
"appIdOrName": "ID do aplicativo ou nome",
|
||||||
"appId": "ID do aplicativo",
|
"appId": "ID do aplicativo",
|
||||||
"appWithIdOrNameNotFound": "Nenhum aplicativo foi encontrado com esse ID ou nome",
|
"appWithIdOrNameNotFound": "Nenhum aplicativo foi encontrado com esse ID ou nome",
|
||||||
"reposHaveMultipleApps": "Repositórios podem conter multiplos aplicativos",
|
"reposHaveMultipleApps": "Repositórios podem conter múltiplos aplicativos",
|
||||||
"fdroidThirdPartyRepo": "Repositórios de terceiros F-Droid",
|
"fdroidThirdPartyRepo": "Repositórios de terceiros F-Droid",
|
||||||
"steamMobile": "Vapor Móvel",
|
"steamMobile": "Steam para celular",
|
||||||
"steamChat": "Bate-papo Steam",
|
"steamChat": "Chat do Steam",
|
||||||
"install": "Instalar",
|
"install": "Instalar",
|
||||||
"markInstalled": "Marcar instalado",
|
"markInstalled": "Marcar instalado",
|
||||||
"update": "Atualizar",
|
"update": "Atualizar",
|
||||||
@ -191,7 +190,7 @@
|
|||||||
"categories": "Categorias",
|
"categories": "Categorias",
|
||||||
"category": "Categoria",
|
"category": "Categoria",
|
||||||
"noCategory": "Sem categoria",
|
"noCategory": "Sem categoria",
|
||||||
"noCategories": "Sem categoria",
|
"noCategories": "Sem categorias",
|
||||||
"deleteCategoriesQuestion": "Deletar categorias?",
|
"deleteCategoriesQuestion": "Deletar categorias?",
|
||||||
"categoryDeleteWarning": "Todos os aplicativos em categorias removidas serão descategorizados.",
|
"categoryDeleteWarning": "Todos os aplicativos em categorias removidas serão descategorizados.",
|
||||||
"addCategory": "Adicionar categoria",
|
"addCategory": "Adicionar categoria",
|
||||||
@ -200,15 +199,15 @@
|
|||||||
"copiedToClipboard": "Copiado para a área de transferência",
|
"copiedToClipboard": "Copiado para a área de transferência",
|
||||||
"storagePermissionDenied": "Permissão de armazenamento negada",
|
"storagePermissionDenied": "Permissão de armazenamento negada",
|
||||||
"selectedCategorizeWarning": "Isso vai substituir qualquer configuração de categoria para os aplicativos selecionados.",
|
"selectedCategorizeWarning": "Isso vai substituir qualquer configuração de categoria para os aplicativos selecionados.",
|
||||||
"filterAPKsByRegEx": "Filtrar APKs por expressão regular",
|
"filterAPKsByRegEx": "Filtrar APKs usando expressão regular",
|
||||||
"removeFromObtainium": "Remover do Obtainium",
|
"removeFromObtainium": "Remover do Obtainium",
|
||||||
"uninstallFromDevice": "Desinstalar do dispositivo",
|
"uninstallFromDevice": "Desinstalar do dispositivo",
|
||||||
"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,10 +215,10 @@
|
|||||||
"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 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",
|
||||||
"about": "Sobre",
|
"about": "Sobre",
|
||||||
"requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)",
|
"requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)",
|
||||||
"checkOnStart": "Verificar se há atualizações ao iniciar",
|
"checkOnStart": "Verificar se há atualizações ao iniciar",
|
||||||
@ -228,12 +227,11 @@
|
|||||||
"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.",
|
||||||
"githubSourceNote": "A limitação de taxa do GitHub pode ser evitada usando uma chave de API.",
|
"githubSourceNote": "A limitação de taxa do GitHub pode ser evitada usando uma chave de API.",
|
||||||
"gitlabSourceNote": "A extração de endereço de download do APK no GitLab provavelmente não funcione sem que seja fornecido uma chave de API.",
|
|
||||||
"sortByLastLinkSegment": "Ordenar apenas usando o último segmento do link",
|
"sortByLastLinkSegment": "Ordenar apenas usando o último segmento do link",
|
||||||
"filterReleaseNotesByRegEx": "Filtrar notas de versão usando Regex",
|
"filterReleaseNotesByRegEx": "Filtrar notas de versão usando Regex",
|
||||||
"customLinkFilterRegex": "Filtro de link personalizado usando expressão regular (Padrão '.apk$')",
|
"customLinkFilterRegex": "Filtro de link personalizado usando expressão regular (Padrão '.apk$')",
|
||||||
@ -254,7 +252,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",
|
||||||
@ -272,18 +270,18 @@
|
|||||||
"updatesAvailableNotifChannel": "Atualizações disponíveis",
|
"updatesAvailableNotifChannel": "Atualizações disponíveis",
|
||||||
"appsUpdatedNotifChannel": "Aplicativos atualizados",
|
"appsUpdatedNotifChannel": "Aplicativos atualizados",
|
||||||
"appsPossiblyUpdatedNotifChannel": "Tentativas de atualização de aplicativos",
|
"appsPossiblyUpdatedNotifChannel": "Tentativas de atualização de aplicativos",
|
||||||
"errorCheckingUpdatesNotifChannel": "Erro ao Procurar por Atualizações",
|
"errorCheckingUpdatesNotifChannel": "Erro ao procurar por atualizações",
|
||||||
"appsRemovedNotifChannel": "Aplicativos removidos",
|
"appsRemovedNotifChannel": "Aplicativos removidos",
|
||||||
"downloadingXNotifChannel": "Baixando {}",
|
"downloadingXNotifChannel": "Baixando {}",
|
||||||
"completeAppInstallationNotifChannel": "Instalação completa do aplicativo",
|
"completeAppInstallationNotifChannel": "Instalação completa do aplicativo",
|
||||||
"checkingForUpdatesNotifChannel": "Checando por Atualizações",
|
"checkingForUpdatesNotifChannel": "Checando por atualizações",
|
||||||
"onlyCheckInstalledOrTrackOnlyApps": "Apenas checar aplicativos instalados e 'Apenas Seguir' por updates",
|
"onlyCheckInstalledOrTrackOnlyApps": "Apenas verificar atualizações de aplicativos instalados e 'Apenas monitorar'",
|
||||||
"supportFixedAPKURL": "Suporte a APK com URLs fixas",
|
"supportFixedAPKURL": "Suporte a APK com URLs fixas",
|
||||||
"selectX": "Selecionar {}",
|
"selectX": "Selecionar {}",
|
||||||
"parallelDownloads": "Permitir downloads paralelos",
|
"parallelDownloads": "Permitir downloads paralelos",
|
||||||
"installMethod": "Método de instalação",
|
"installMethod": "Método de instalação",
|
||||||
"normal": "Normal",
|
"normal": "Normal",
|
||||||
"root": "Raiz",
|
"root": "Root",
|
||||||
"shizukuBinderNotFound": "O Shizuku não está rodando",
|
"shizukuBinderNotFound": "O Shizuku não está rodando",
|
||||||
"useSystemFont": "Usar fonte padrão do sistema",
|
"useSystemFont": "Usar fonte padrão do sistema",
|
||||||
"systemFontError": "Erro ao carregar a fonte do sistema: {}",
|
"systemFontError": "Erro ao carregar a fonte do sistema: {}",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Instalado",
|
"installed": "Instalado",
|
||||||
"latest": "Mais recente",
|
"latest": "Mais recente",
|
||||||
"invertRegEx": "Inverter expressão regular",
|
"invertRegEx": "Inverter expressão regular",
|
||||||
|
"note": "Nota",
|
||||||
|
"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?"
|
||||||
@ -339,15 +340,19 @@
|
|||||||
"other": "Foram limpos {n} logs (antes = {antes}, depois = {depois})"
|
"other": "Foram limpos {n} logs (antes = {antes}, depois = {depois})"
|
||||||
},
|
},
|
||||||
"xAndNMoreUpdatesAvailable": {
|
"xAndNMoreUpdatesAvailable": {
|
||||||
"one": "{} e 1 outro aplicativo possui atualizações.",
|
"one": "{} e um outro aplicativo possui atualizações.",
|
||||||
"other": "{} e {} outros aplicativo possuem atualizações."
|
"other": "{} e {} outros aplicativo possuem atualizações."
|
||||||
},
|
},
|
||||||
"xAndNMoreUpdatesInstalled": {
|
"xAndNMoreUpdatesInstalled": {
|
||||||
"one": "{} e um outro aplicativo foi atualizado.",
|
"one": "{} e um outro aplicativo foram atualizado.",
|
||||||
"other": "{} e {} outros aplicativos foram atualizados."
|
"other": "{} e {} outros aplicativos foram atualizados."
|
||||||
},
|
},
|
||||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
"one": "{} e 1 outro aplicativo pode ter sido atualizado.",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@
|
|||||||
"removeOutdatedFilter": "Удалить фильтр для устаревших приложений",
|
"removeOutdatedFilter": "Удалить фильтр для устаревших приложений",
|
||||||
"showOutdatedOnly": "Показывать только устаревшие приложения",
|
"showOutdatedOnly": "Показывать только устаревшие приложения",
|
||||||
"filter": "Фильтр",
|
"filter": "Фильтр",
|
||||||
"filterActive": "Фильтр *",
|
|
||||||
"filterApps": "Фильтровать приложения",
|
"filterApps": "Фильтровать приложения",
|
||||||
"appName": "Название приложения",
|
"appName": "Название приложения",
|
||||||
"author": "Автор",
|
"author": "Автор",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Не показывать предупреждения о только отслеживаемых приложениях",
|
"dontShowTrackOnlyWarnings": "Не показывать предупреждения о только отслеживаемых приложениях",
|
||||||
"dontShowAPKOriginWarnings": "Не показывать предупреждения об отличающемся источнике APK-файлов",
|
"dontShowAPKOriginWarnings": "Не показывать предупреждения об отличающемся источнике APK-файлов",
|
||||||
"moveNonInstalledAppsToBottom": "Отображать неустановленные приложения внизу списка",
|
"moveNonInstalledAppsToBottom": "Отображать неустановленные приложения внизу списка",
|
||||||
"gitlabPATLabel": "Персональный токен доступа GitLab\n(включает поиск и улучшает обнаружение APK)",
|
"gitlabPATLabel": "Персональный токен доступа GitLab",
|
||||||
"about": "Описание",
|
"about": "Описание",
|
||||||
"requiresCredentialsInSettings": "{}: Для этого требуются дополнительные учетные данные (в настройках)",
|
"requiresCredentialsInSettings": "{}: Для этого требуются дополнительные учетные данные (в настройках)",
|
||||||
"checkOnStart": "Проверять наличие обновлений при запуске",
|
"checkOnStart": "Проверять наличие обновлений при запуске",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Добавьте эту информацию ниже",
|
"addInfoBelow": "Добавьте эту информацию ниже",
|
||||||
"addInfoInSettings": "Добавьте эту информацию в Настройки",
|
"addInfoInSettings": "Добавьте эту информацию в Настройки",
|
||||||
"githubSourceNote": "Используя ключ API можно обойти лимит запросов GitHub",
|
"githubSourceNote": "Используя ключ API можно обойти лимит запросов GitHub",
|
||||||
"gitlabSourceNote": "Без ключа API может не работать извлечение APK с GitLab",
|
|
||||||
"sortByLastLinkSegment": "Сортировать только по последнему сегменту ссылки",
|
"sortByLastLinkSegment": "Сортировать только по последнему сегменту ссылки",
|
||||||
"filterReleaseNotesByRegEx": "Фильтровать примечания к выпуску\n(регулярное выражение)",
|
"filterReleaseNotesByRegEx": "Фильтровать примечания к выпуску\n(регулярное выражение)",
|
||||||
"customLinkFilterRegex": "Пользовательский фильтр ссылок APK\n(регулярное выражение, по умолчанию: '.apk$')",
|
"customLinkFilterRegex": "Пользовательский фильтр ссылок APK\n(регулярное выражение, по умолчанию: '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Установлен",
|
"installed": "Установлен",
|
||||||
"latest": "Последний",
|
"latest": "Последний",
|
||||||
"invertRegEx": "Инвертировать регулярное выражение",
|
"invertRegEx": "Инвертировать регулярное выражение",
|
||||||
|
"note": "Примечание",
|
||||||
|
"selfHostedNote": "Выпадающий список \"{}\" можно использовать для доступа к самостоятельно размещенным/настроенным экземплярам любого источника.",
|
||||||
|
"badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Удалить приложение?",
|
"one": "Удалить приложение?",
|
||||||
"other": "Удалить приложения?"
|
"other": "Удалить приложения?"
|
||||||
@ -349,5 +350,9 @@
|
|||||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
"one": "{} и ещё 1 приложение могли быть обновлены",
|
"one": "{} и ещё 1 приложение могли быть обновлены",
|
||||||
"other": "{} и ещё {} приложений могли быть обновлены"
|
"other": "{} и ещё {} приложений могли быть обновлены"
|
||||||
|
},
|
||||||
|
"apk": {
|
||||||
|
"one": "{} APK",
|
||||||
|
"other": "{} APKs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Visa inte 'Följ-Endast' varningar",
|
"dontShowTrackOnlyWarnings": "Visa inte 'Följ-Endast' varningar",
|
||||||
"dontShowAPKOriginWarnings": "Visa inte APK-ursprung varningar",
|
"dontShowAPKOriginWarnings": "Visa inte APK-ursprung varningar",
|
||||||
"moveNonInstalledAppsToBottom": "Flytta icke-installerade appar till botten av appvyn",
|
"moveNonInstalledAppsToBottom": "Flytta icke-installerade appar till botten av appvyn",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token\\n(Möjliggör sökning och bättre APK-upptäckt)",
|
"gitlabPATLabel": "GitLab Personal Access Token",
|
||||||
"about": "Om",
|
"about": "Om",
|
||||||
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "{}: This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Kolla efter uppdateringar vid start",
|
"checkOnStart": "Kolla efter uppdateringar vid start",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Lägg till denna information nedanför.",
|
"addInfoBelow": "Lägg till denna information nedanför.",
|
||||||
"addInfoInSettings": "Lägg till denna information i Inställningar.",
|
"addInfoInSettings": "Lägg till denna information i Inställningar.",
|
||||||
"githubSourceNote": "GitHub-hastighetsbegränsning kan undvikas med en API-nyckel.",
|
"githubSourceNote": "GitHub-hastighetsbegränsning kan undvikas med en API-nyckel.",
|
||||||
"gitlabSourceNote": "GitLab APK-extraktion kanske inte fungerar utan en API-nyckel.",
|
|
||||||
"sortByLastLinkSegment": "Sortera endast efter det sista segmentet av länken",
|
"sortByLastLinkSegment": "Sortera endast efter det sista segmentet av länken",
|
||||||
"filterReleaseNotesByRegEx": "Filtrera versionskommentarer efter reguljärt uttryck",
|
"filterReleaseNotesByRegEx": "Filtrera versionskommentarer efter reguljärt uttryck",
|
||||||
"customLinkFilterRegex": "Anpassad APK-länkfiltrera efter reguljärt uttryck (standard '.apk$')",
|
"customLinkFilterRegex": "Anpassad APK-länkfiltrera efter reguljärt uttryck (standard '.apk$')",
|
||||||
@ -288,16 +286,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": "Anmärkning",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
@ -219,7 +218,7 @@
|
|||||||
"dontShowTrackOnlyWarnings": "'Yalnızca Takip Edilen' uyarılarını gösterme",
|
"dontShowTrackOnlyWarnings": "'Yalnızca Takip Edilen' uyarılarını gösterme",
|
||||||
"dontShowAPKOriginWarnings": "APK kaynağı uyarılarını gösterme",
|
"dontShowAPKOriginWarnings": "APK kaynağı uyarılarını gösterme",
|
||||||
"moveNonInstalledAppsToBottom": "Yüklenmemiş Uygulamaları Uygulamalar Görünümünün Altına Taşı",
|
"moveNonInstalledAppsToBottom": "Yüklenmemiş Uygulamaları Uygulamalar Görünümünün Altına Taşı",
|
||||||
"gitlabPATLabel": "GitLab Kişisel Erişim Belirteci\n(Arama ve Daha İyi APK Keşfi İçin)",
|
"gitlabPATLabel": "GitLab Kişisel Erişim Belirteci",
|
||||||
"about": "Hakkında",
|
"about": "Hakkında",
|
||||||
"requiresCredentialsInSettings": "{}: Bu, ek kimlik bilgilerine ihtiyaç duyar (Ayarlar'da)",
|
"requiresCredentialsInSettings": "{}: Bu, ek kimlik bilgilerine ihtiyaç duyar (Ayarlar'da)",
|
||||||
"checkOnStart": "Başlangıçta güncellemeleri kontrol et",
|
"checkOnStart": "Başlangıçta güncellemeleri kontrol et",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "Bu bilgiyi aşağıya ekle.",
|
"addInfoBelow": "Bu bilgiyi aşağıya ekle.",
|
||||||
"addInfoInSettings": "Bu bilgiyi Ayarlar'da ekleyin.",
|
"addInfoInSettings": "Bu bilgiyi Ayarlar'da ekleyin.",
|
||||||
"githubSourceNote": "GitHub hız sınırlaması bir API anahtarı kullanılarak atlanabilir.",
|
"githubSourceNote": "GitHub hız sınırlaması bir API anahtarı kullanılarak atlanabilir.",
|
||||||
"gitlabSourceNote": "GitLab APK çıkarma işlemi bir API anahtarı olmadan çalışmayabilir.",
|
|
||||||
"sortByLastLinkSegment": "Bağlantının yalnızca son bölümüne göre sırala",
|
"sortByLastLinkSegment": "Bağlantının yalnızca son bölümüne göre sırala",
|
||||||
"filterReleaseNotesByRegEx": "Sürüm Notlarını Düzenli İfade ile Filtrele",
|
"filterReleaseNotesByRegEx": "Sürüm Notlarını Düzenli İfade ile Filtrele",
|
||||||
"customLinkFilterRegex": "Özel APK Bağlantı Filtresi Düzenli İfade ile (Varsayılan '.apk$')",
|
"customLinkFilterRegex": "Özel APK Bağlantı Filtresi Düzenli İfade ile (Varsayılan '.apk$')",
|
||||||
@ -298,6 +296,9 @@
|
|||||||
"installed": "Kurulmuş",
|
"installed": "Kurulmuş",
|
||||||
"latest": "En sonuncu",
|
"latest": "En sonuncu",
|
||||||
"invertRegEx": "Normal ifadeyi ters çevir",
|
"invertRegEx": "Normal ifadeyi ters çevir",
|
||||||
|
"note": "Not",
|
||||||
|
"selfHostedNote": "\"{}\" açı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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
359
assets/translations/uk.json
Normal file
359
assets/translations/uk.json
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
{
|
||||||
|
"invalidURLForSource": "Неправильна URL-адреса для джерела застосунку {}",
|
||||||
|
"noReleaseFound": "Не вдалося знайти відповідне видання",
|
||||||
|
"noVersionFound": "Не вдалося визначити версію видання",
|
||||||
|
"urlMatchesNoSource": "URL не відповідає відомому джерелу",
|
||||||
|
"cantInstallOlderVersion": "Не можна встановити старішу версію застосунку",
|
||||||
|
"appIdMismatch": "Ідентифікатор пакета, завантажений, не відповідає ідентифікатору існуючого застосунку",
|
||||||
|
"functionNotImplemented": "Цей клас не реалізував цю функцію",
|
||||||
|
"placeholder": "Заповнювач",
|
||||||
|
"someErrors": "Виникла деяка помилка",
|
||||||
|
"unexpectedError": "Неочікувана помилка",
|
||||||
|
"ok": "Добре",
|
||||||
|
"and": "та",
|
||||||
|
"githubPATLabel": "Персональний ключ доступу GitHub (збільшує обмеження на швидкість)",
|
||||||
|
"includePrereleases": "Включити попередні видання",
|
||||||
|
"fallbackToOlderReleases": "Повернутися до старіших видань",
|
||||||
|
"filterReleaseTitlesByRegEx": "Фільтрувати заголовки видань за допомогою регулярного виразу",
|
||||||
|
"invalidRegEx": "Неприпустимий регулярний вираз",
|
||||||
|
"noDescription": "Немає опису",
|
||||||
|
"cancel": "Скасувати",
|
||||||
|
"continue": "Продовжити",
|
||||||
|
"requiredInBrackets": "(Обов'язково)",
|
||||||
|
"dropdownNoOptsError": "ПОМИЛКА: В ВИПАДАЮЧОМУ СПИСКУ МАЄ БУТИ ХОЧА Б ОДИН ЕЛЕМЕНТ",
|
||||||
|
"colour": "Колір",
|
||||||
|
"githubStarredRepos": "Відзначені репозиторії GitHub",
|
||||||
|
"uname": "Ім'я користувача",
|
||||||
|
"wrongArgNum": "Надано неправильну кількість аргументів",
|
||||||
|
"xIsTrackOnly": "{} - тільки відстежування",
|
||||||
|
"source": "Джерело",
|
||||||
|
"app": "застосунок",
|
||||||
|
"appsFromSourceAreTrackOnly": "Додатки з цього джерела є лише для відстежування.",
|
||||||
|
"youPickedTrackOnly": "Ви вибрали опцію лише для відстежування.",
|
||||||
|
"trackOnlyAppDescription": "Застосунок буде відстежуватися для оновлень, але Obtainium не зможе його завантажити або встановити.",
|
||||||
|
"cancelled": "Скасовано",
|
||||||
|
"appAlreadyAdded": "Застосунок вже додано",
|
||||||
|
"alreadyUpToDateQuestion": "Застосунок вже оновлено?",
|
||||||
|
"addApp": "Додати Застосунок",
|
||||||
|
"appSourceURL": "URL-адреса джерела застосунку",
|
||||||
|
"error": "Помилка",
|
||||||
|
"add": "Додати",
|
||||||
|
"searchSomeSourcesLabel": "Пошук (Лише деякі джерела)",
|
||||||
|
"search": "Пошук",
|
||||||
|
"additionalOptsFor": "Додаткові опції для {}",
|
||||||
|
"supportedSources": "Підтримувані джерела",
|
||||||
|
"trackOnlyInBrackets": "(Тільки для відстеження)",
|
||||||
|
"searchableInBrackets": "(Можливий пошук)",
|
||||||
|
"appsString": "Додатки",
|
||||||
|
"noApps": "Додатків немає",
|
||||||
|
"noAppsForFilter": "Додатків для фільтрації немає",
|
||||||
|
"byX": "За {}",
|
||||||
|
"percentProgress": "Прогрес: {}%",
|
||||||
|
"pleaseWait": "Будь ласка, зачекайте",
|
||||||
|
"updateAvailable": "Доступно оновлення",
|
||||||
|
"notInstalled": "Не встановлено",
|
||||||
|
"pseudoVersion": "псевдо-версія",
|
||||||
|
"selectAll": "Вибрати все",
|
||||||
|
"deselectX": "Скасувати вибір {}",
|
||||||
|
"xWillBeRemovedButRemainInstalled": "{} буде видалено з Obtainium, але залишиться встановленим на пристрої.",
|
||||||
|
"removeSelectedAppsQuestion": "Видалити вибрані додатки?",
|
||||||
|
"removeSelectedApps": "Видалити вибрані додатки",
|
||||||
|
"updateX": "Оновити {}",
|
||||||
|
"installX": "Встановити {}",
|
||||||
|
"markXTrackOnlyAsUpdated": "Позначити {}\n(Тільки відстежування)\nяк оновлено",
|
||||||
|
"changeX": "Змінити {}",
|
||||||
|
"installUpdateApps": "Встановити/Оновити додатки",
|
||||||
|
"installUpdateSelectedApps": "Встановити/Оновити вибрані додатки",
|
||||||
|
"markXSelectedAppsAsUpdated": "Позначити {} вибрані додатки як оновлені?",
|
||||||
|
"no": "Ні",
|
||||||
|
"yes": "Так",
|
||||||
|
"markSelectedAppsUpdated": "Позначити вибрані додатки як оновлені",
|
||||||
|
"pinToTop": "Закріпити угорі",
|
||||||
|
"unpinFromTop": "Відкріпити зверху",
|
||||||
|
"resetInstallStatusForSelectedAppsQuestion": "Скинути статус встановлення для вибраних додатків?",
|
||||||
|
"installStatusOfXWillBeResetExplanation": "Статус встановлення будь-яких вибраних додатків буде скинутий.\n\nЦе може допомогти, коли версія застосунку, відображена в Obtainium, є неправильною через невдалі оновлення або інші проблеми.",
|
||||||
|
"customLinkMessage": "Ці посилання працюють на пристроях з встановленим Obtainium",
|
||||||
|
"shareAppConfigLinks": "Поділитися посиланнями на конфігурацію Застосунку як HTML",
|
||||||
|
"shareSelectedAppURLs": "Поділитися вибраними URL-адресами додатків",
|
||||||
|
"resetInstallStatus": "Скинути статус встановлення",
|
||||||
|
"more": "Більше",
|
||||||
|
"removeOutdatedFilter": "Видалити фільтр застарілих додатків",
|
||||||
|
"showOutdatedOnly": "Показати лише застарілі додатки",
|
||||||
|
"filter": "Фільтр",
|
||||||
|
"filterApps": "Фільтрувати додатки",
|
||||||
|
"appName": "Назва застосунку",
|
||||||
|
"author": "Автор",
|
||||||
|
"upToDateApps": "Актуальні додатки",
|
||||||
|
"nonInstalledApps": "Невстановлені додатки",
|
||||||
|
"importExport": "Імпорт/Експорт",
|
||||||
|
"settings": "Налаштування",
|
||||||
|
"exportedTo": "Експортовано в {}",
|
||||||
|
"obtainiumExport": "Експорт з Obtainium",
|
||||||
|
"invalidInput": "Недійсний ввід",
|
||||||
|
"importedX": "Імпортовано {}",
|
||||||
|
"obtainiumImport": "Імпорт в Obtainium",
|
||||||
|
"importFromURLList": "Імпорт зі списку URL-адрес",
|
||||||
|
"searchQuery": "Пошуковий запит",
|
||||||
|
"appURLList": "Список URL-адрес додатків",
|
||||||
|
"line": "Лінія",
|
||||||
|
"searchX": "Пошук {}",
|
||||||
|
"noResults": "Результати відсутні",
|
||||||
|
"importX": "Імпорт {}",
|
||||||
|
"importedAppsIdDisclaimer": "Імпортовані додатки можуть неправильно відображатися як \"Не встановлені\".\nДля виправлення цього перевстановіть їх через Obtainium.\nЦе не повинно вплинути на дані додатків.\n\nПов'язано лише з URL-адресами та імпортом від третіх сторін.",
|
||||||
|
"importErrors": "Помилки імпорту",
|
||||||
|
"importedXOfYApps": "Імпортовано {} з {} додатків.",
|
||||||
|
"followingURLsHadErrors": "Помилки в наступних URL-адресах:",
|
||||||
|
"selectURL": "Вибрати URL",
|
||||||
|
"selectURLs": "Вибрати URL-адреси",
|
||||||
|
"pick": "Вибрати",
|
||||||
|
"theme": "Тема",
|
||||||
|
"dark": "Темна",
|
||||||
|
"light": "Світла",
|
||||||
|
"followSystem": "Дотримуватися системи",
|
||||||
|
"useBlackTheme": "Використовувати чисто чорну темну тему",
|
||||||
|
"appSortBy": "Сортувати додатки за",
|
||||||
|
"authorName": "Автор/Назва",
|
||||||
|
"nameAuthor": "Назва/Автор",
|
||||||
|
"asAdded": "За додаванням",
|
||||||
|
"appSortOrder": "Порядок сортування додатків",
|
||||||
|
"ascending": "За зростанням",
|
||||||
|
"descending": "За спаданням",
|
||||||
|
"bgUpdateCheckInterval": "Інтервал перевірки оновлень у фоновому режимі",
|
||||||
|
"neverManualOnly": "Ніколи - Тільки вручну",
|
||||||
|
"appearance": "Вигляд",
|
||||||
|
"showWebInAppView": "Показати джерело застосунку у вигляді веб-сторінки",
|
||||||
|
"pinUpdates": "Закріпити оновлення у верхній частині вигляду додатків",
|
||||||
|
"updates": "Оновлення",
|
||||||
|
"sourceSpecific": "Певне джерело",
|
||||||
|
"appSource": "Джерело застосунку",
|
||||||
|
"noLogs": "Немає логів",
|
||||||
|
"appLogs": "Лог застосунку",
|
||||||
|
"close": "Закрити",
|
||||||
|
"share": "Поділитися",
|
||||||
|
"appNotFound": "Застосунок не знайдено",
|
||||||
|
"obtainiumExportHyphenatedLowercase": "експорт з Obtainium",
|
||||||
|
"pickAnAPK": "Вибрати APK",
|
||||||
|
"appHasMoreThanOnePackage": "{} має більше одного пакету:",
|
||||||
|
"deviceSupportsXArch": "Ваш пристрій підтримує архітектуру процесора {}.",
|
||||||
|
"deviceSupportsFollowingArchs": "Ваш пристрій підтримує наступні архітектури процесора:",
|
||||||
|
"warning": "Попередження",
|
||||||
|
"sourceIsXButPackageFromYPrompt": "Джерело застосунку - '{}' але пакет випуску походить з '{}'. Продовжити?",
|
||||||
|
"updatesAvailable": "Доступні оновлення",
|
||||||
|
"updatesAvailableNotifDescription": "Повідомляє користувача, що доступні оновлення для одного чи декількох додатків, які відстежує Obtainium",
|
||||||
|
"noNewUpdates": "Немає нових оновлень.",
|
||||||
|
"xHasAnUpdate": "{} має оновлення.",
|
||||||
|
"appsUpdated": "Додатки оновлено",
|
||||||
|
"appsUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного чи декількох додатків було застосовано в фоновому режимі",
|
||||||
|
"xWasUpdatedToY": "{} було оновлено до {}.",
|
||||||
|
"errorCheckingUpdates": "Помилка перевірки оновлень",
|
||||||
|
"errorCheckingUpdatesNotifDescription": "Повідомлення, яке з'являється, коли перевірка оновлень в фоновому режимі завершується невдачею",
|
||||||
|
"appsRemoved": "Додатки видалено",
|
||||||
|
"appsRemovedNotifDescription": "Повідомляє користувача, що один чи декілька додатків були видалені через помилки при завантаженні",
|
||||||
|
"xWasRemovedDueToErrorY": "{} було видалено через цю помилку: {}",
|
||||||
|
"completeAppInstallation": "Завершення установки застосунку",
|
||||||
|
"obtainiumMustBeOpenToInstallApps": "Для встановлення додатків Obtainium має бути відкритий",
|
||||||
|
"completeAppInstallationNotifDescription": "Прохання користувача повернутися до Obtainium для завершення установки застосунку",
|
||||||
|
"checkingForUpdates": "Перевірка оновлень",
|
||||||
|
"checkingForUpdatesNotifDescription": "Тимчасове повідомлення, яке з'являється при перевірці оновлень",
|
||||||
|
"pleaseAllowInstallPerm": "Будь ласка, дозвольте Obtainium встановлювати додатки",
|
||||||
|
"trackOnly": "Тільки відстеження",
|
||||||
|
"errorWithHttpStatusCode": "Помилка {} HTTP-коду",
|
||||||
|
"versionCorrectionDisabled": "Виправлення версії вимкнено (здається, плагін не працює)",
|
||||||
|
"unknown": "Невідомо",
|
||||||
|
"none": "Нічого",
|
||||||
|
"never": "Ніколи",
|
||||||
|
"latestVersionX": "Остання версія: {}",
|
||||||
|
"installedVersionX": "Встановлено: {}",
|
||||||
|
"lastUpdateCheckX": "Остання перевірка оновлень: {}",
|
||||||
|
"remove": "Видалити",
|
||||||
|
"yesMarkUpdated": "Так, позначити як оновлене",
|
||||||
|
"fdroid": "F-Droid Офіційний",
|
||||||
|
"appIdOrName": "Ідентифікатор або назва застосунку",
|
||||||
|
"appId": "Ідентифікатор застосунку",
|
||||||
|
"appWithIdOrNameNotFound": "Застосунок з таким ідентифікатором або назвою не знайдено",
|
||||||
|
"reposHaveMultipleApps": "Сховища можуть містити кілька додатків",
|
||||||
|
"fdroidThirdPartyRepo": "F-Droid Стороннє сховище",
|
||||||
|
"steamMobile": "Мобільний Steam",
|
||||||
|
"steamChat": "Чат Steam",
|
||||||
|
"install": "Встановити",
|
||||||
|
"markInstalled": "Позначити як встановлене",
|
||||||
|
"update": "Оновити",
|
||||||
|
"markUpdated": "Позначити як оновлене",
|
||||||
|
"additionalOptions": "Додаткові опції",
|
||||||
|
"disableVersionDetection": "Вимкнути визначення версії",
|
||||||
|
"noVersionDetectionExplanation": "Цю опцію слід використовувати лише для додатків, де визначення версії працює неправильно.",
|
||||||
|
"downloadingX": "Завантаження {}",
|
||||||
|
"downloadNotifDescription": "Повідомляє користувача про прогрес завантаження застосунку",
|
||||||
|
"noAPKFound": "APK не знайдено",
|
||||||
|
"noVersionDetection": "Визначення версії відключено",
|
||||||
|
"categorize": "Категоризувати",
|
||||||
|
"categories": "Категорії",
|
||||||
|
"category": "Категорія",
|
||||||
|
"noCategory": "Без категорії",
|
||||||
|
"noCategories": "Немає категорій",
|
||||||
|
"deleteCategoriesQuestion": "Видалити категорії?",
|
||||||
|
"categoryDeleteWarning": "Усі додатки у видалених категоріях будуть переведені у некатегоризовані.",
|
||||||
|
"addCategory": "Додати категорію",
|
||||||
|
"label": "Мітка",
|
||||||
|
"language": "Мова",
|
||||||
|
"copiedToClipboard": "Скопійовано в буфер обміну",
|
||||||
|
"storagePermissionDenied": "Відмовлено у дозволі на доступ до сховища",
|
||||||
|
"selectedCategorizeWarning": "Це замінить будь-які існуючі налаштування категорій для вибраних додатків.",
|
||||||
|
"filterAPKsByRegEx": "Фільтрувати APK за регулярним виразом",
|
||||||
|
"removeFromObtainium": "Видалити з Obtainium",
|
||||||
|
"uninstallFromDevice": "Видалити з пристрою",
|
||||||
|
"onlyWorksWithNonVersionDetectApps": "Працює лише з застосунками з вимкненим визначенням версії.",
|
||||||
|
"releaseDateAsVersion": "Використовувати дату випуску як рядок версії",
|
||||||
|
"releaseDateAsVersionExplanation": "Цю опцію слід використовувати лише для додатків, де визначення версії працює неправильно, але є дата випуску.",
|
||||||
|
"changes": "Зміни",
|
||||||
|
"releaseDate": "Дата випуску",
|
||||||
|
"importFromURLsInFile": "Імпорт з URL-адрес у файлі (наприклад, OPML)",
|
||||||
|
"versionDetectionExplanation": "Порівняти рядок версії з версією, визначеною операційною системою",
|
||||||
|
"versionDetection": "Визначення версії",
|
||||||
|
"standardVersionDetection": "Стандартне визначення версії",
|
||||||
|
"groupByCategory": "Групувати за категоріями",
|
||||||
|
"autoApkFilterByArch": "Спробувати фільтрувати APK за архітектурою ЦП, якщо можливо",
|
||||||
|
"overrideSource": "Перевизначити джерело",
|
||||||
|
"dontShowAgain": "Не показувати це знову",
|
||||||
|
"dontShowTrackOnlyWarnings": "Не показувати попередження про 'Тільки відстеження'",
|
||||||
|
"dontShowAPKOriginWarnings": "Не показувати попередження про походження APK",
|
||||||
|
"moveNonInstalledAppsToBottom": "Перемістити невстановлені додатки вниз у перегляді додатків",
|
||||||
|
"gitlabPATLabel": "Особистий токен GitLab (Увімкнення пошуку та краще виявлення APK)",
|
||||||
|
"about": "Про програму",
|
||||||
|
"requiresCredentialsInSettings": "{} потребує додаткових облікових даних (у налаштуваннях)",
|
||||||
|
"checkOnStart": "Перевірити наявність оновлень при запуску",
|
||||||
|
"tryInferAppIdFromCode": "Спробувати вивести ідентифікатор застосунку з вихідного коду",
|
||||||
|
"removeOnExternalUninstall": "Автоматично видаляти додатки, які було видалено зовнішнім чином",
|
||||||
|
"pickHighestVersionCode": "Автоматично вибрати APK з найвищим кодом версії",
|
||||||
|
"checkUpdateOnDetailPage": "Перевіряти наявність оновлень при відкритті сторінки деталей застосунку",
|
||||||
|
"disablePageTransitions": "Вимкнути анімації переходів між сторінками",
|
||||||
|
"reversePageTransitions": "Зворотні анімації переходів між сторінками",
|
||||||
|
"minStarCount": "Мінімальна кількість зірок",
|
||||||
|
"addInfoBelow": "Додати цю інформацію нижче.",
|
||||||
|
"addInfoInSettings": "Додати цю інформацію у налаштуваннях.",
|
||||||
|
"githubSourceNote": "Лімітування швидкості GitHub можна уникнути, використовуючи ключ API.",
|
||||||
|
"gitlabSourceNote": "Вилучення APK з GitLab може не працювати без ключа API.",
|
||||||
|
"sortByLastLinkSegment": "Сортувати лише за останнім сегментом посилання",
|
||||||
|
"filterReleaseNotesByRegEx": "Фільтрувати примітки до релізу за регулярним виразом",
|
||||||
|
"customLinkFilterRegex": "Фільтр кастомного посилання на APK за регулярним виразом (за замовчуванням '.apk$')",
|
||||||
|
"appsPossiblyUpdated": "Оновлення додатків спробовано",
|
||||||
|
"appsPossiblyUpdatedNotifDescription": "Повідомляє користувача, що оновлення одного або декількох додатків можливо були застосовані в фоновому режимі",
|
||||||
|
"xWasPossiblyUpdatedToY": "{} можливо було оновлено до {}.",
|
||||||
|
"enableBackgroundUpdates": "Увімкнути оновлення в фоновому режимі",
|
||||||
|
"backgroundUpdateReqsExplanation": "Оновлення в фоновому режимі може бути неможливим для всіх додатків.",
|
||||||
|
"backgroundUpdateLimitsExplanation": "Успіх фонової установки може бути визначений лише після відкриття Obtainium.",
|
||||||
|
"verifyLatestTag": "Перевірити тег 'latest'",
|
||||||
|
"intermediateLinkRegex": "Фільтр для 'Проміжного' Посилання для Відвідування",
|
||||||
|
"filterByLinkText": "Фільтрувати посилання за текстом посилання",
|
||||||
|
"intermediateLinkNotFound": "Проміжне посилання не знайдено",
|
||||||
|
"intermediateLink": "Проміжне посилання",
|
||||||
|
"exemptFromBackgroundUpdates": "Виключено з фонових оновлень (якщо ввімкнено)",
|
||||||
|
"bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi",
|
||||||
|
"autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії",
|
||||||
|
"versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії",
|
||||||
|
"matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії",
|
||||||
|
"highlightTouchTargets": "Підсвічувати менш очевидні області дотику",
|
||||||
|
"pickExportDir": "Вибрати каталог експорту",
|
||||||
|
"autoExportOnChanges": "Автоматичний експорт при змінах",
|
||||||
|
"includeSettings": "Включити налаштування",
|
||||||
|
"filterVersionsByRegEx": "Фільтрувати версії за регулярним виразом",
|
||||||
|
"trySelectingSuggestedVersionCode": "Спробуйте вибрати запропонований код версії APK",
|
||||||
|
"dontSortReleasesList": "Зберігати порядок випуску з API",
|
||||||
|
"reverseSort": "Зворотне сортування",
|
||||||
|
"takeFirstLink": "Вибрати перше посилання",
|
||||||
|
"skipSort": "Пропустити сортування",
|
||||||
|
"debugMenu": "Меню налагодження",
|
||||||
|
"bgTaskStarted": "Запущено фонове завдання - перевірте журнали.",
|
||||||
|
"runBgCheckNow": "Запустити перевірку оновлень в фоновому режимі зараз",
|
||||||
|
"versionExtractWholePage": "Застосувати регулярний вираз вилучення версії до всієї сторінки",
|
||||||
|
"installing": "Встановлення",
|
||||||
|
"skipUpdateNotifications": "Пропустити сповіщення про оновлення",
|
||||||
|
"updatesAvailableNotifChannel": "Доступні оновлення",
|
||||||
|
"appsUpdatedNotifChannel": "Додатки оновлені",
|
||||||
|
"appsPossiblyUpdatedNotifChannel": "Спроба оновлення додатків",
|
||||||
|
"errorCheckingUpdatesNotifChannel": "Помилка перевірки оновлень",
|
||||||
|
"appsRemovedNotifChannel": "Додатки видалені",
|
||||||
|
"downloadingXNotifChannel": "Завантаження {}",
|
||||||
|
"completeAppInstallationNotifChannel": "Завершення встановлення застосунку",
|
||||||
|
"checkingForUpdatesNotifChannel": "Перевірка оновлень",
|
||||||
|
"onlyCheckInstalledOrTrackOnlyApps": "Перевіряти лише встановлені та додатки, які відстежуються для оновлень",
|
||||||
|
"supportFixedAPKURL": "Підтримка фіксованих посилань на APK",
|
||||||
|
"selectX": "Вибрати {}",
|
||||||
|
"parallelDownloads": "Дозволити паралельні завантаження",
|
||||||
|
"installMethod": "Метод встановлення",
|
||||||
|
"normal": "Звичайний",
|
||||||
|
"root": "Root",
|
||||||
|
"shizukuBinderNotFound": "Сумісний сервіс Shizuku не було знайдено",
|
||||||
|
"useSystemFont": "Використовувати системний шрифт",
|
||||||
|
"systemFontError": "Помилка завантаження системного шрифту: {}",
|
||||||
|
"useVersionCodeAsOSVersion": "Використовувати код версії застосунку як версію, визначену операційною системою",
|
||||||
|
"requestHeader": "Заголовок запиту",
|
||||||
|
"useLatestAssetDateAsReleaseDate": "Використовувати останню дату завантаження ресурсу як дату випуску",
|
||||||
|
"defaultPseudoVersioningMethod": "Метод за замовчуванням псевдо-версіонування",
|
||||||
|
"partialAPKHash": "Хеш часткового APK",
|
||||||
|
"APKLinkHash": "Хеш посилання на APK",
|
||||||
|
"directAPKLink": "Пряме посилання на APK",
|
||||||
|
"pseudoVersionInUse": "Використовується псевдо-версія",
|
||||||
|
"installed": "Встановлено",
|
||||||
|
"latest": "Остання",
|
||||||
|
"invertRegEx": "Інвертувати регулярний вираз",
|
||||||
|
"note": "Примітка",
|
||||||
|
"selfHostedNote": "Випадаючий список \"{}\" може використовуватися для доступу до власних/призначених для самостійного використання екземплярів будь-якого джерела.",
|
||||||
|
"badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)",
|
||||||
|
"removeAppQuestion": {
|
||||||
|
"one": "Видалити Застосунок?",
|
||||||
|
"other": "Видалити додатки?"
|
||||||
|
},
|
||||||
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
|
"one": "Забагато запитів (обмеження швидкості) - повторіть спробу через {} хвилину",
|
||||||
|
"other": "Забагато запитів (обмеження швидкості) - повторіть спробу через {} хвилин"
|
||||||
|
},
|
||||||
|
"bgUpdateGotErrorRetryInMinutes": {
|
||||||
|
"one": "Помилка перевірки оновлень у фоновому режимі - спробую знову через {} хвилину",
|
||||||
|
"other": "Помилка перевірки оновлень у фоновому режимі - спробую знову через {} хвилин"
|
||||||
|
},
|
||||||
|
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||||
|
"one": "Фонова перевірка оновлень знайшла {} оновлення - сповістить користувача, якщо це необхідно",
|
||||||
|
"other": "Фонова перевірка оновлень знайшла {} оновлень - сповістить користувача, якщо це необхідно"
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"one": "{} Застосунок",
|
||||||
|
"other": "{} Додатки"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"one": "{} URL",
|
||||||
|
"other": "{} URL-адреси"
|
||||||
|
},
|
||||||
|
"minute": {
|
||||||
|
"one": "{} Хвилина",
|
||||||
|
"other": "{} Хвилин"
|
||||||
|
},
|
||||||
|
"hour": {
|
||||||
|
"one": "{} Година",
|
||||||
|
"other": "{} Годин"
|
||||||
|
},
|
||||||
|
"day": {
|
||||||
|
"one": "{} День",
|
||||||
|
"other": "{} Днів"
|
||||||
|
},
|
||||||
|
"clearedNLogsBeforeXAfterY": {
|
||||||
|
"one": "Очищено {n} журнал (до = {before}, після = {after})",
|
||||||
|
"other": "Очищено {n} журналів (до = {before}, після = {after})"
|
||||||
|
},
|
||||||
|
"xAndNMoreUpdatesAvailable": {
|
||||||
|
"one": "{} і 1 інше Застосунок мають оновлення.",
|
||||||
|
"other": "{} і {} інших додатки мають оновлення."
|
||||||
|
},
|
||||||
|
"xAndNMoreUpdatesInstalled": {
|
||||||
|
"one": "{} і 1 інше Застосунок було оновлено.",
|
||||||
|
"other": "{} і {} інших додатків було оновлено."
|
||||||
|
},
|
||||||
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
|
"one": "{} і 1 інше Застосунок можливо було оновлено.",
|
||||||
|
"other": "{} і {} інших додатків можливо було оновлено."
|
||||||
|
},
|
||||||
|
"apk": {
|
||||||
|
"one": "{} APK",
|
||||||
|
"other": "{} APK-файли"
|
||||||
|
}
|
||||||
|
}
|
@ -25,11 +25,11 @@
|
|||||||
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
|
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
|
||||||
"uname": "Tên người dùng",
|
"uname": "Tên người dùng",
|
||||||
"wrongArgNum": "Số lượng đối số được cung cấp sai",
|
"wrongArgNum": "Số lượng đối số được cung cấp sai",
|
||||||
"xIsTrackOnly": "{}là Chỉ-Theo dõi",
|
"xIsTrackOnly": "{} là Chỉ theo dõi",
|
||||||
"source": "Nguồn",
|
"source": "Nguồn",
|
||||||
"app": "Ứng dụng",
|
"app": "Ứng dụng",
|
||||||
"appsFromSourceAreTrackOnly": "Các ứng dụng từ nguồn này là 'Chỉ-Theo dõi'.",
|
"appsFromSourceAreTrackOnly": "Các ứng dụng từ nguồn này là 'Chỉ theo dõi'.",
|
||||||
"youPickedTrackOnly": "Bạn đã chọn tùy chọn 'Chỉ-Theo dõi'.",
|
"youPickedTrackOnly": "Bạn đã chọn tùy chọn 'Chỉ theo dõi'.",
|
||||||
"trackOnlyAppDescription": "Ứng dụng sẽ được theo dõi để cập nhật, nhưng Obtainium sẽ không thể tải xuống hoặc cài đặt nó.",
|
"trackOnlyAppDescription": "Ứng dụng sẽ được theo dõi để cập nhật, nhưng Obtainium sẽ không thể tải xuống hoặc cài đặt nó.",
|
||||||
"cancelled": "Đã hủy",
|
"cancelled": "Đã hủy",
|
||||||
"appAlreadyAdded": "Ứng dụng được thêm rồi",
|
"appAlreadyAdded": "Ứng dụng được thêm rồi",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"search": "Tìm kiếm",
|
"search": "Tìm kiếm",
|
||||||
"additionalOptsFor": "Tùy chọn bổ sung cho {}",
|
"additionalOptsFor": "Tùy chọn bổ sung cho {}",
|
||||||
"supportedSources": "Nguồn được hỗ trợ",
|
"supportedSources": "Nguồn được hỗ trợ",
|
||||||
"trackOnlyInBrackets": "(Chỉ-Theo dõi)",
|
"trackOnlyInBrackets": "(Chỉ theo dõi)",
|
||||||
"searchableInBrackets": "(Có thể tìm kiếm)",
|
"searchableInBrackets": "(Có thể tìm kiếm)",
|
||||||
"appsString": "Ứng dụng",
|
"appsString": "Ứng dụng",
|
||||||
"noApps": "Không có ứng dụng",
|
"noApps": "Không có ứng dụng",
|
||||||
@ -60,7 +60,7 @@
|
|||||||
"removeSelectedApps": "Xóa ứng dụng đã chọn",
|
"removeSelectedApps": "Xóa ứng dụng đã chọn",
|
||||||
"updateX": "Cập nhật {}",
|
"updateX": "Cập nhật {}",
|
||||||
"installX": "Cài đặt {}",
|
"installX": "Cài đặt {}",
|
||||||
"markXTrackOnlyAsUpdated": "Đánh dấu {}\n(Chỉ-Theo dõi)\nnhư là đã cập nhật",
|
"markXTrackOnlyAsUpdated": "Đánh dấu {}\n(Chỉ theo dõi)\nnhư là đã cập nhật",
|
||||||
"changeX": "Thay đổi {}",
|
"changeX": "Thay đổi {}",
|
||||||
"installUpdateApps": "Cài đặt/Cập nhật ứng dụng",
|
"installUpdateApps": "Cài đặt/Cập nhật ứng dụng",
|
||||||
"installUpdateSelectedApps": "Cài đặt/Cập nhật ứng dụng đã chọn",
|
"installUpdateSelectedApps": "Cài đặt/Cập nhật ứng dụng đã chọn",
|
||||||
@ -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,16 +211,16 @@
|
|||||||
"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",
|
||||||
"dontShowTrackOnlyWarnings": "Không hiển thị cảnh báo 'Chỉ theo dõi'",
|
"dontShowTrackOnlyWarnings": "Không hiển thị cảnh báo 'Chỉ theo dõi'",
|
||||||
"dontShowAPKOriginWarnings": "Không hiển thị cảnh báo nguồn gốc APK",
|
"dontShowAPKOriginWarnings": "Không hiển thị cảnh báo nguồn gốc APK",
|
||||||
"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",
|
||||||
"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,9 +230,8 @@
|
|||||||
"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.",
|
|
||||||
"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",
|
||||||
"filterReleaseNotesByRegEx": "Lọc ghi chú phát hành theo biểu thức chính quy",
|
"filterReleaseNotesByRegEx": "Lọc ghi chú phát hành theo biểu thức chính quy",
|
||||||
"customLinkFilterRegex": "Bộ lọc liên kết APK tùy chỉnh theo biểu thức chính quy (Mặc định '.apk$')",
|
"customLinkFilterRegex": "Bộ lọc liên kết APK tùy chỉnh theo biểu thức chính quy (Mặc định '.apk$')",
|
||||||
@ -256,7 +254,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",
|
||||||
@ -277,7 +275,7 @@
|
|||||||
"downloadingXNotifChannel": "Đang tải xuống {}",
|
"downloadingXNotifChannel": "Đang tải xuống {}",
|
||||||
"completeAppInstallationNotifChannel": "Hoàn tất cài đặt ứng dụng",
|
"completeAppInstallationNotifChannel": "Hoàn tất cài đặt ứng dụng",
|
||||||
"checkingForUpdatesNotifChannel": "Đang kiểm tra cập nhật",
|
"checkingForUpdatesNotifChannel": "Đang kiểm tra cập nhật",
|
||||||
"onlyCheckInstalledOrTrackOnlyApps": "Chỉ kiểm tra cập nhật các ứng dụng đã cài đặt và Chỉ-Theo dõi",
|
"onlyCheckInstalledOrTrackOnlyApps": "Chỉ kiểm tra cập nhật các ứng dụng đã cài đặt và Chỉ theo dõi",
|
||||||
"supportFixedAPKURL": "Hỗ trợ URL APK cố định",
|
"supportFixedAPKURL": "Hỗ trợ URL APK cố định",
|
||||||
"selectX": "Lựa chọn {}",
|
"selectX": "Lựa chọn {}",
|
||||||
"parallelDownloads": "Cho phép tải đa luồng",
|
"parallelDownloads": "Cho phép tải đa luồng",
|
||||||
@ -295,9 +293,12 @@
|
|||||||
"APKLinkHash": "Băm liên kết APK",
|
"APKLinkHash": "Băm liên kết APK",
|
||||||
"directAPKLink": "Liên kết APK trực tiếp",
|
"directAPKLink": "Liên kết APK trực tiếp",
|
||||||
"pseudoVersionInUse": "Phiên bản giả đang được sử dụng",
|
"pseudoVersionInUse": "Phiên bản giả đang được sử dụng",
|
||||||
"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": "Ghi chú",
|
||||||
|
"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?"
|
||||||
@ -349,5 +350,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
"pleaseWait": "请稍候",
|
"pleaseWait": "请稍候",
|
||||||
"updateAvailable": "更新可用",
|
"updateAvailable": "更新可用",
|
||||||
"notInstalled": "未安装",
|
"notInstalled": "未安装",
|
||||||
"pseudoVersion": "伪版本",
|
"pseudoVersion": "虚拟版本号",
|
||||||
"selectAll": "全选",
|
"selectAll": "全选",
|
||||||
"deselectX": "取消选择 {}",
|
"deselectX": "取消选择 {}",
|
||||||
"xWillBeRemovedButRemainInstalled": "“{}”将从 Obtainium 中删除,但仍安装在您的设备中。",
|
"xWillBeRemovedButRemainInstalled": "“{}”将从 Obtainium 中删除,但仍安装在您的设备中。",
|
||||||
@ -80,7 +80,6 @@
|
|||||||
"removeOutdatedFilter": "删除失效的应用筛选",
|
"removeOutdatedFilter": "删除失效的应用筛选",
|
||||||
"showOutdatedOnly": "只显示待更新应用",
|
"showOutdatedOnly": "只显示待更新应用",
|
||||||
"filter": "筛选",
|
"filter": "筛选",
|
||||||
"filterActive": "筛选 *",
|
|
||||||
"filterApps": "筛选应用",
|
"filterApps": "筛选应用",
|
||||||
"appName": "应用名称",
|
"appName": "应用名称",
|
||||||
"author": "作者",
|
"author": "作者",
|
||||||
@ -209,7 +208,7 @@
|
|||||||
"changes": "更新日志",
|
"changes": "更新日志",
|
||||||
"releaseDate": "发行日期",
|
"releaseDate": "发行日期",
|
||||||
"importFromURLsInFile": "从文件中的 URL 导入(如 OPML)",
|
"importFromURLsInFile": "从文件中的 URL 导入(如 OPML)",
|
||||||
"versionDetectionExplanation": "将版本字符串与操作系统检测到的版本进行协调",
|
"versionDetectionExplanation": "使发行版本号与应用定义的版本号一致",
|
||||||
"versionDetection": "版本检测",
|
"versionDetection": "版本检测",
|
||||||
"standardVersionDetection": "常规版本检测",
|
"standardVersionDetection": "常规版本检测",
|
||||||
"groupByCategory": "按类别分组显示",
|
"groupByCategory": "按类别分组显示",
|
||||||
@ -219,13 +218,13 @@
|
|||||||
"dontShowTrackOnlyWarnings": "忽略“仅追踪”模式警告",
|
"dontShowTrackOnlyWarnings": "忽略“仅追踪”模式警告",
|
||||||
"dontShowAPKOriginWarnings": "忽略 APK 文件来源警告",
|
"dontShowAPKOriginWarnings": "忽略 APK 文件来源警告",
|
||||||
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
||||||
"gitlabPATLabel": "GitLab 个人访问令牌(启用搜索功能并增强 APK 发现)",
|
"gitlabPATLabel": "GitLab 个人访问令牌",
|
||||||
"about": "相关文档",
|
"about": "相关文档",
|
||||||
"requiresCredentialsInSettings": "{}:此功能需要额外的凭据(在“设置”中添加)",
|
"requiresCredentialsInSettings": "{}:此功能需要额外的凭据(在“设置”中添加)",
|
||||||
"checkOnStart": "启动时进行一次检查",
|
"checkOnStart": "启动时进行一次检查",
|
||||||
"tryInferAppIdFromCode": "尝试从源代码推断应用 ID",
|
"tryInferAppIdFromCode": "尝试从源代码推断应用 ID",
|
||||||
"removeOnExternalUninstall": "自动删除列表中已卸载的应用",
|
"removeOnExternalUninstall": "自动删除列表中已卸载的应用",
|
||||||
"pickHighestVersionCode": "自动选择版本号最高的 APK 文件",
|
"pickHighestVersionCode": "自动选取内部版本号最高的 APK 文件",
|
||||||
"checkUpdateOnDetailPage": "打开应用详情页时进行检查",
|
"checkUpdateOnDetailPage": "打开应用详情页时进行检查",
|
||||||
"disablePageTransitions": "禁用页面过渡动画效果",
|
"disablePageTransitions": "禁用页面过渡动画效果",
|
||||||
"reversePageTransitions": "反转页面过渡动画效果",
|
"reversePageTransitions": "反转页面过渡动画效果",
|
||||||
@ -233,7 +232,6 @@
|
|||||||
"addInfoBelow": "在下方添加此凭据。",
|
"addInfoBelow": "在下方添加此凭据。",
|
||||||
"addInfoInSettings": "在“设置”中添加此凭据。",
|
"addInfoInSettings": "在“设置”中添加此凭据。",
|
||||||
"githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。",
|
"githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。",
|
||||||
"gitlabSourceNote": "未使用访问令牌时可能无法从 GitLab 获取 APK 文件。",
|
|
||||||
"sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选",
|
"sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选",
|
||||||
"filterReleaseNotesByRegEx": "筛选发行说明(正则表达式)",
|
"filterReleaseNotesByRegEx": "筛选发行说明(正则表达式)",
|
||||||
"customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n(正则表达式,默认匹配模式为“.apk$”)",
|
"customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n(正则表达式,默认匹配模式为“.apk$”)",
|
||||||
@ -250,7 +248,7 @@
|
|||||||
"intermediateLink": "中转链接",
|
"intermediateLink": "中转链接",
|
||||||
"exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)",
|
"exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)",
|
||||||
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
|
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
|
||||||
"autoSelectHighestVersionCode": "自动选择版本号最高的 APK 文件",
|
"autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件",
|
||||||
"versionExtractionRegEx": "版本号提取规则(正则表达式)",
|
"versionExtractionRegEx": "版本号提取规则(正则表达式)",
|
||||||
"matchGroupToUse": "引用的捕获组",
|
"matchGroupToUse": "引用的捕获组",
|
||||||
"highlightTouchTargets": "突出展示不明显的触摸区域",
|
"highlightTouchTargets": "突出展示不明显的触摸区域",
|
||||||
@ -287,17 +285,20 @@
|
|||||||
"shizukuBinderNotFound": "未发现兼容的 Shizuku 服务",
|
"shizukuBinderNotFound": "未发现兼容的 Shizuku 服务",
|
||||||
"useSystemFont": "使用系统字体",
|
"useSystemFont": "使用系统字体",
|
||||||
"systemFontError": "加载系统字体出错:{}",
|
"systemFontError": "加载系统字体出错:{}",
|
||||||
"useVersionCodeAsOSVersion": "使用应用程序版本代码作为操作系统检测到的版本",
|
"useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号",
|
||||||
"requestHeader": "请求标头",
|
"requestHeader": "请求标头",
|
||||||
"useLatestAssetDateAsReleaseDate": "使用最新资产上传作为发布日期",
|
"useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期",
|
||||||
"defaultPseudoVersioningMethod": "默认伪版本控制方法",
|
"defaultPseudoVersioningMethod": "默认虚拟版本方案",
|
||||||
"partialAPKHash": "部分 APK 哈希值",
|
"partialAPKHash": "APK 文件散列值片段",
|
||||||
"APKLinkHash": "APK 链接哈希",
|
"APKLinkHash": "APK 文件链接散列值",
|
||||||
"directAPKLink": "直接 APK 链接",
|
"directAPKLink": "APK 文件直链",
|
||||||
"pseudoVersionInUse": "伪版本正在使用",
|
"pseudoVersionInUse": "正在使用虚拟版本号",
|
||||||
"installed": "已安装",
|
"installed": "当前版本",
|
||||||
"latest": "最新的",
|
"latest": "最新版本",
|
||||||
"invertRegEx": "反转正则表达式",
|
"invertRegEx": "反转匹配",
|
||||||
|
"note": "备注",
|
||||||
|
"selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。",
|
||||||
|
"badDownload": "无法解析 APK 文件(不兼容或文件不完整)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "是否删除应用?",
|
"one": "是否删除应用?",
|
||||||
"other": "是否删除应用?"
|
"other": "是否删除应用?"
|
||||||
@ -349,5 +350,9 @@
|
|||||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||||
"one": "{} 和另外 1 个应用已尝试更新。",
|
"one": "{} 和另外 1 个应用已尝试更新。",
|
||||||
"other": "“{}”和另外 {} 个应用已尝试更新。"
|
"other": "“{}”和另外 {} 个应用已尝试更新。"
|
||||||
|
},
|
||||||
|
"apk": {
|
||||||
|
"one": "{}APK",
|
||||||
|
"other": "{}APK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
build.sh
1
build.sh
@ -8,6 +8,7 @@ if [ -z "$1" ]; then
|
|||||||
git fetch && git merge origin/main && git push # Typically run after a PR to main, so bring dev up to date
|
git fetch && git merge origin/main && git push # Typically run after a PR to main, so bring dev up to date
|
||||||
fi
|
fi
|
||||||
cd .flutter
|
cd .flutter
|
||||||
|
git fetch
|
||||||
git checkout "$(flutter --version | head -2 | tail -1 | awk '{print $4}')" # Ensure included Flutter submodule version equals my environment
|
git checkout "$(flutter --version | head -2 | tail -1 | awk '{print $4}')" # Ensure included Flutter submodule version equals my environment
|
||||||
cd ..
|
cd ..
|
||||||
rm ./build/app/outputs/flutter-apk/* 2>/dev/null # Get rid of older builds if any
|
rm ./build/app/outputs/flutter-apk/* 2>/dev/null # Get rid of older builds if any
|
||||||
|
@ -45,7 +45,7 @@ class APKCombo extends AppSource {
|
|||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
return html
|
return html
|
||||||
.querySelectorAll('#variants-tab > div > ul > li')
|
.querySelectorAll('#variants-tab > div > ul > li')
|
||||||
.map((e) {
|
.map((e) {
|
||||||
@ -96,7 +96,7 @@ class APKCombo extends AppSource {
|
|||||||
if (preres.statusCode != 200) {
|
if (preres.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(preres);
|
throw getObtainiumHttpError(preres);
|
||||||
}
|
}
|
||||||
var res = parse(preres.body);
|
var res = parse(preres.data);
|
||||||
String? version = res.querySelector('div.version')?.text.trim();
|
String? version = res.querySelector('div.version')?.text.trim();
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
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';
|
||||||
@ -62,7 +62,7 @@ class APKMirror extends AppSource {
|
|||||||
: null;
|
: null;
|
||||||
Response res = await sourceRequest('$standardUrl/feed', additionalSettings);
|
Response res = await sourceRequest('$standardUrl/feed', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var items = parse(res.body).querySelectorAll('item');
|
var items = parse(res.data).querySelectorAll('item');
|
||||||
dynamic targetRelease;
|
dynamic targetRelease;
|
||||||
for (int i = 0; i < items.length; i++) {
|
for (int i = 0; i < items.length; i++) {
|
||||||
if (!fallbackToOlderReleases && i > 0) break;
|
if (!fallbackToOlderReleases && i > 0) break;
|
||||||
|
@ -61,8 +61,8 @@ class APKPure extends AppSource {
|
|||||||
var res = await sourceRequest('$standardUrl/download', additionalSettings);
|
var res = await sourceRequest('$standardUrl/download', additionalSettings);
|
||||||
var resChangelog = await sourceRequest(standardUrl, additionalSettings);
|
var resChangelog = await sourceRequest(standardUrl, additionalSettings);
|
||||||
if (res.statusCode == 200 && resChangelog.statusCode == 200) {
|
if (res.statusCode == 200 && resChangelog.statusCode == 200) {
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
var htmlChangelog = parse(resChangelog.body);
|
var htmlChangelog = parse(resChangelog.data);
|
||||||
String? version = html.querySelector('span.info-sdk span')?.text.trim();
|
String? version = html.querySelector('span.info-sdk span')?.text.trim();
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
|
@ -38,10 +38,10 @@ class Aptoide extends AppSource {
|
|||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var idMatch = RegExp('"app":{"id":[0-9]+').firstMatch(res.body);
|
var idMatch = RegExp('"app":{"id":[0-9]+').firstMatch(res.data);
|
||||||
String? id;
|
String? id;
|
||||||
if (idMatch != null) {
|
if (idMatch != null) {
|
||||||
id = res.body.substring(idMatch.start + 12, idMatch.end);
|
id = res.data.substring(idMatch.start + 12, idMatch.end);
|
||||||
} else {
|
} else {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ class Aptoide extends AppSource {
|
|||||||
if (res2.statusCode != 200) {
|
if (res2.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
return jsonDecode(res2.body)?['nodes']?['meta']?['data'];
|
return jsonDecode(res2.data)?['nodes']?['meta']?['data'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
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/app_sources/github.dart';
|
||||||
|
import 'package:obtainium/app_sources/gitlab.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';
|
||||||
@ -74,38 +76,44 @@ 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(
|
||||||
'https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/$appId.yml',
|
'https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/$appId.yml',
|
||||||
additionalSettings);
|
additionalSettings);
|
||||||
var lines = res.body.split('\n');
|
var lines = res.data.split('\n');
|
||||||
var authorLines = lines.where((l) => l.startsWith('AuthorName: '));
|
var authorLines = lines.where((l) => l.startsWith('AuthorName: '));
|
||||||
if (authorLines.isNotEmpty) {
|
if (authorLines.isNotEmpty) {
|
||||||
details.names.author =
|
details.names.author =
|
||||||
authorLines.first.split(': ').sublist(1).join(': ');
|
authorLines.first.split(': ').sublist(1).join(': ');
|
||||||
}
|
}
|
||||||
var changelogUrls = lines.where((l) => l.startsWith('Changelog: '));
|
var changelogUrls = lines
|
||||||
|
.where((l) => l.startsWith('Changelog: '))
|
||||||
|
.map((e) => e.split(' ').sublist(1).join(' '));
|
||||||
if (changelogUrls.isNotEmpty) {
|
if (changelogUrls.isNotEmpty) {
|
||||||
details.changeLog = changelogUrls.first;
|
details.changeLog = changelogUrls.first;
|
||||||
details.changeLog = (await sourceRequest(
|
bool isGitHub = false;
|
||||||
details.changeLog!
|
bool isGitLab = false;
|
||||||
.split(': ')
|
try {
|
||||||
.sublist(1)
|
GitHub().sourceSpecificStandardizeURL(details.changeLog!);
|
||||||
.join(': ')
|
isGitHub = true;
|
||||||
.replaceFirst('/blob/', '/raw/'),
|
} catch (e) {
|
||||||
additionalSettings))
|
//
|
||||||
.body;
|
}
|
||||||
|
try {
|
||||||
|
GitLab().sourceSpecificStandardizeURL(details.changeLog!);
|
||||||
|
isGitLab = true;
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if ((isGitHub || isGitLab) &&
|
||||||
|
(details.changeLog?.indexOf('/blob/') ?? -1) >= 0) {
|
||||||
|
details.changeLog = (await sourceRequest(
|
||||||
|
details.changeLog!.replaceFirst('/blob/', '/raw/'),
|
||||||
|
additionalSettings))
|
||||||
|
.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fail silently
|
// Fail silently
|
||||||
@ -124,7 +132,7 @@ class FDroid extends AppSource {
|
|||||||
'https://search.${hosts[0]}/?q=${Uri.encodeQueryComponent(query)}', {});
|
'https://search.${hosts[0]}/?q=${Uri.encodeQueryComponent(query)}', {});
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
Map<String, List<String>> urlsWithDescriptions = {};
|
Map<String, List<String>> urlsWithDescriptions = {};
|
||||||
parse(res.body).querySelectorAll('.package-header').forEach((e) {
|
parse(res.data).querySelectorAll('.package-header').forEach((e) {
|
||||||
String? url = e.attributes['href'];
|
String? url = e.attributes['href'];
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
try {
|
try {
|
||||||
@ -149,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.data);
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
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:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.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,9 +61,10 @@ class FDroidRepo extends AppSource {
|
|||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
url = removeQueryParamsFromUrl(standardizeUrl(url));
|
url = removeQueryParamsFromUrl(standardizeUrl(url));
|
||||||
var res = await sourceRequest('$url/index.xml', {});
|
var ress = await sourceRequestWithURLVariants(url, {});
|
||||||
|
var res = ress.value;
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var body = parse(res.body);
|
var body = parse(res.data);
|
||||||
Map<String, List<String>> results = {};
|
Map<String, List<String>> results = {};
|
||||||
body.querySelectorAll('application').toList().forEach((app) {
|
body.querySelectorAll('application').toList().forEach((app) {
|
||||||
String appId = app.attributes['id']!;
|
String appId = app.attributes['id']!;
|
||||||
@ -72,7 +74,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[
|
||||||
|
'${ress.value.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}?appId=$appId'] = [
|
||||||
|
appName,
|
||||||
|
appDesc
|
||||||
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
@ -102,6 +108,26 @@ class FDroidRepo extends AppSource {
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<MapEntry<String, Response>> sourceRequestWithURLVariants(
|
||||||
|
String url,
|
||||||
|
Map<String, dynamic> additionalSettings,
|
||||||
|
) async {
|
||||||
|
var finalUrl = '$url${url.endsWith('/index.xml') ? '' : '/index.xml'}';
|
||||||
|
var res = await sourceRequest(finalUrl, additionalSettings);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
var base = url.endsWith('/index.xml')
|
||||||
|
? url.split('/').reversed.toList().sublist(1).reversed.join('/')
|
||||||
|
: url;
|
||||||
|
finalUrl = '$base/repo/index.xml';
|
||||||
|
res = await sourceRequest(finalUrl, additionalSettings);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
finalUrl = '$base/fdroid/repo/index.xml';
|
||||||
|
res = await sourceRequest(finalUrl, additionalSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MapEntry(finalUrl, res);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl,
|
String standardUrl,
|
||||||
@ -117,11 +143,11 @@ class FDroidRepo extends AppSource {
|
|||||||
if (appIdOrName == null) {
|
if (appIdOrName == null) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
var res = await sourceRequest(
|
var ress =
|
||||||
'$standardUrl${standardUrl.endsWith('/index.xml') ? '' : '/index.xml'}',
|
await sourceRequestWithURLVariants(standardUrl, additionalSettings);
|
||||||
additionalSettings);
|
var res = ress.value;
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var body = parse(res.body);
|
var body = parse(res.data);
|
||||||
var foundApps = body.querySelectorAll('application').where((element) {
|
var foundApps = body.querySelectorAll('application').where((element) {
|
||||||
return element.attributes['id'] == appIdOrName;
|
return element.attributes['id'] == appIdOrName;
|
||||||
}).toList();
|
}).toList();
|
||||||
@ -168,7 +194,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) =>
|
||||||
|
'${ress.value.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),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
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:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/html.dart';
|
import 'package:obtainium/app_sources/html.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';
|
||||||
@ -112,12 +112,12 @@ class GitHub extends AppSource {
|
|||||||
];
|
];
|
||||||
for (var path in possibleBuildGradleLocations) {
|
for (var path in possibleBuildGradleLocations) {
|
||||||
try {
|
try {
|
||||||
var res = await sourceRequest(
|
var finalUrl =
|
||||||
'${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/contents/$path',
|
'${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/contents/$path';
|
||||||
additionalSettings);
|
var res = await sourceRequest(finalUrl, additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
try {
|
try {
|
||||||
var body = jsonDecode(res.body);
|
var body = jsonDecode(res.data);
|
||||||
var trimmedLines = utf8
|
var trimmedLines = utf8
|
||||||
.decode(base64
|
.decode(base64
|
||||||
.decode(body['content'].toString().split('\n').join('')))
|
.decode(body['content'].toString().split('\n').join('')))
|
||||||
@ -143,7 +143,7 @@ class GitHub extends AppSource {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
LogsProvider().add(
|
LogsProvider().add(
|
||||||
'Error parsing build.gradle from ${res.request!.url.toString()}: ${err.toString()}');
|
'Error parsing build.gradle from $finalUrl: ${err.toString()}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -256,11 +256,11 @@ class GitHub extends AppSource {
|
|||||||
}
|
}
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
latestRelease = jsonDecode(res.body);
|
latestRelease = jsonDecode(res.data);
|
||||||
}
|
}
|
||||||
Response res = await sourceRequest(requestUrl, additionalSettings);
|
Response res = await sourceRequest(requestUrl, additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var releases = jsonDecode(res.body) as List<dynamic>;
|
var releases = jsonDecode(res.data) as List<dynamic>;
|
||||||
if (latestRelease != null) {
|
if (latestRelease != null) {
|
||||||
var latestTag = latestRelease['tag_name'] ?? latestRelease['name'];
|
var latestTag = latestRelease['tag_name'] ?? latestRelease['name'];
|
||||||
if (releases
|
if (releases
|
||||||
@ -344,12 +344,14 @@ class GitHub extends AppSource {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (latestRelease != null &&
|
if (latestRelease != null &&
|
||||||
|
(latestRelease['tag_name'] ?? latestRelease['name']) != null &&
|
||||||
releases.isNotEmpty &&
|
releases.isNotEmpty &&
|
||||||
latestRelease !=
|
latestRelease !=
|
||||||
(releases[releases.length - 1]['tag_name'] ??
|
(releases[releases.length - 1]['tag_name'] ??
|
||||||
releases[0]['name'])) {
|
releases[0]['name'])) {
|
||||||
var ind = releases.indexWhere((element) =>
|
var ind = releases.indexWhere((element) =>
|
||||||
latestRelease == (element['tag_name'] ?? element['name']));
|
(latestRelease['tag_name'] ?? latestRelease['name']) ==
|
||||||
|
(element['tag_name'] ?? element['name']));
|
||||||
if (ind >= 0) {
|
if (ind >= 0) {
|
||||||
releases.add(releases.removeAt(ind));
|
releases.add(releases.removeAt(ind));
|
||||||
}
|
}
|
||||||
@ -400,7 +402,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>>,
|
||||||
@ -464,7 +466,7 @@ class GitHub extends AppSource {
|
|||||||
? int.parse(querySettings['minStarCount'])
|
? int.parse(querySettings['minStarCount'])
|
||||||
: 0;
|
: 0;
|
||||||
Map<String, List<String>> urlsWithDescriptions = {};
|
Map<String, List<String>> urlsWithDescriptions = {};
|
||||||
for (var e in (jsonDecode(res.body)[rootProp] as List<dynamic>)) {
|
for (var e in (jsonDecode(res.data)[rootProp] as List<dynamic>)) {
|
||||||
if ((e['stargazers_count'] ?? e['stars_count'] ?? 0) >= minStarCount) {
|
if ((e['stargazers_count'] ?? e['stars_count'] ?? 0) >= minStarCount) {
|
||||||
urlsWithDescriptions.addAll({
|
urlsWithDescriptions.addAll({
|
||||||
e['html_url'] as String: [
|
e['html_url'] as String: [
|
||||||
@ -498,11 +500,13 @@ class GitHub extends AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rateLimitErrorCheck(Response res) {
|
rateLimitErrorCheck(Response res) {
|
||||||
if (res.headers['x-ratelimit-remaining'] == '0') {
|
String? rateLimitHeader;
|
||||||
|
if (res.headers.map['x-ratelimit-remaining']?.isNotEmpty == true) {
|
||||||
|
rateLimitHeader = res.headers.map['x-ratelimit-remaining']![0];
|
||||||
|
}
|
||||||
|
if (rateLimitHeader == '0') {
|
||||||
throw RateLimitError(
|
throw RateLimitError(
|
||||||
(int.parse(res.headers['x-ratelimit-reset'] ?? '1800000000') /
|
(int.parse(rateLimitHeader ?? '1800000000') / 60000000).round());
|
||||||
60000000)
|
|
||||||
.round());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:html/parser.dart';
|
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/github.dart';
|
import 'package:obtainium/app_sources/github.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/providers/settings_provider.dart';
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
@ -72,14 +72,6 @@ class GitLab extends AppSource {
|
|||||||
return creds != null && creds.isNotEmpty ? creds : null;
|
return creds != null && creds.isNotEmpty ? creds : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String?> getSourceNote() async {
|
|
||||||
if ((await getPATIfAny({})) == null) {
|
|
||||||
return '${tr('gitlabSourceNote')} ${hostChanged ? tr('addInfoBelow') : tr('addInfoInSettings')}';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query,
|
Future<Map<String, List<String>>> search(String query,
|
||||||
{Map<String, dynamic> querySettings = const {}}) async {
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
@ -89,7 +81,7 @@ class GitLab extends AppSource {
|
|||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var json = jsonDecode(res.body) as List<dynamic>;
|
var json = jsonDecode(res.data) as List<dynamic>;
|
||||||
Map<String, List<String>> results = {};
|
Map<String, List<String>> results = {};
|
||||||
for (var element in json) {
|
for (var element in json) {
|
||||||
results['https://${hosts[0]}/${element['path_with_namespace']}'] = [
|
results['https://${hosts[0]}/${element['path_with_namespace']}'] = [
|
||||||
@ -104,105 +96,87 @@ 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,
|
||||||
Map<String, dynamic> additionalSettings,
|
Map<String, dynamic> additionalSettings,
|
||||||
) async {
|
) async {
|
||||||
|
// Prepare request params
|
||||||
|
var names = GitHub().getAppNames(standardUrl);
|
||||||
|
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
|
||||||
|
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
|
||||||
|
|
||||||
|
// Request data from REST API
|
||||||
|
Response res = await sourceRequest(
|
||||||
|
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/releases?$optionalAuth',
|
||||||
|
additionalSettings);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
throw getObtainiumHttpError(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract .apk details from received data
|
||||||
|
Iterable<APKDetails> apkDetailsList = [];
|
||||||
|
var json = jsonDecode(res.data) as List<dynamic>;
|
||||||
|
apkDetailsList = json.map((e) {
|
||||||
|
var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? [])
|
||||||
|
.map((e) {
|
||||||
|
return (e['direct_asset_url'] ?? e['url'] ?? '') as String;
|
||||||
|
})
|
||||||
|
.where((s) => s.isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
List<String> uploadedAPKsFromDescription =
|
||||||
|
((e['description'] ?? '') as String)
|
||||||
|
.split('](')
|
||||||
|
.join('\n')
|
||||||
|
.split('.apk)')
|
||||||
|
.join('.apk\n')
|
||||||
|
.split('\n')
|
||||||
|
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
|
||||||
|
.map((s) => '$standardUrl$s')
|
||||||
|
.toList();
|
||||||
|
var apkUrlsSet = apkUrlsFromAssets.toSet();
|
||||||
|
apkUrlsSet.addAll(uploadedAPKsFromDescription);
|
||||||
|
var releaseDateString = e['released_at'] ?? e['created_at'];
|
||||||
|
DateTime? releaseDate =
|
||||||
|
releaseDateString != null ? DateTime.parse(releaseDateString) : null;
|
||||||
|
return APKDetails(
|
||||||
|
e['tag_name'] ?? e['name'],
|
||||||
|
getApkUrlsFromUrls(apkUrlsSet.toList()),
|
||||||
|
GitHub().getAppNames(standardUrl),
|
||||||
|
releaseDate: releaseDate);
|
||||||
|
});
|
||||||
|
if (apkDetailsList.isEmpty) {
|
||||||
|
throw NoReleasesError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback procedure
|
||||||
bool fallbackToOlderReleases =
|
bool fallbackToOlderReleases =
|
||||||
additionalSettings['fallbackToOlderReleases'] == true;
|
additionalSettings['fallbackToOlderReleases'] == true;
|
||||||
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
|
|
||||||
Iterable<APKDetails> apkDetailsList = [];
|
|
||||||
if (PAT != null) {
|
|
||||||
var names = GitHub().getAppNames(standardUrl);
|
|
||||||
Response res = await sourceRequest(
|
|
||||||
'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT',
|
|
||||||
additionalSettings);
|
|
||||||
if (res.statusCode != 200) {
|
|
||||||
throw getObtainiumHttpError(res);
|
|
||||||
}
|
|
||||||
var json = jsonDecode(res.body) as List<dynamic>;
|
|
||||||
apkDetailsList = json.map((e) {
|
|
||||||
var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? [])
|
|
||||||
.map((e) {
|
|
||||||
return (e['direct_asset_url'] ?? e['url'] ?? '') as String;
|
|
||||||
})
|
|
||||||
.where((s) => s.isNotEmpty)
|
|
||||||
.toList();
|
|
||||||
List<String> uploadedAPKsFromDescription =
|
|
||||||
((e['description'] ?? '') as String)
|
|
||||||
.split('](')
|
|
||||||
.join('\n')
|
|
||||||
.split('.apk)')
|
|
||||||
.join('.apk\n')
|
|
||||||
.split('\n')
|
|
||||||
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
|
|
||||||
.map((s) => '$standardUrl$s')
|
|
||||||
.toList();
|
|
||||||
var apkUrlsSet = apkUrlsFromAssets.toSet();
|
|
||||||
apkUrlsSet.addAll(uploadedAPKsFromDescription);
|
|
||||||
var releaseDateString = e['released_at'] ?? e['created_at'];
|
|
||||||
DateTime? releaseDate = releaseDateString != null
|
|
||||||
? DateTime.parse(releaseDateString)
|
|
||||||
: null;
|
|
||||||
return APKDetails(
|
|
||||||
e['tag_name'] ?? e['name'],
|
|
||||||
getApkUrlsFromUrls(apkUrlsSet.toList()),
|
|
||||||
GitHub().getAppNames(standardUrl),
|
|
||||||
releaseDate: releaseDate);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Response res = await sourceRequest(
|
|
||||||
'$standardUrl/-/tags?format=atom', additionalSettings);
|
|
||||||
if (res.statusCode != 200) {
|
|
||||||
throw getObtainiumHttpError(res);
|
|
||||||
}
|
|
||||||
var standardUri = Uri.parse(standardUrl);
|
|
||||||
var parsedHtml = parse(res.body);
|
|
||||||
apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) {
|
|
||||||
var entryContent = parse(
|
|
||||||
parseFragment(entry.querySelector('content')!.innerHtml).text);
|
|
||||||
var apkUrls = [
|
|
||||||
...getLinksFromParsedHTML(
|
|
||||||
entryContent,
|
|
||||||
RegExp(
|
|
||||||
'^${standardUri.path.replaceAllMapped(RegExp(r'[.*+?^${}()|[\]\\]'), (x) {
|
|
||||||
return '\\${x[0]}';
|
|
||||||
})}/uploads/[^/]+/[^/]+\\.apk\$',
|
|
||||||
caseSensitive: false),
|
|
||||||
standardUri.origin),
|
|
||||||
// GitLab releases may contain links to externally hosted APKs
|
|
||||||
...getLinksFromParsedHTML(entryContent,
|
|
||||||
RegExp('/[^/]+\\.apk\$', caseSensitive: false), '')
|
|
||||||
.where((element) => Uri.parse(element).host != '')
|
|
||||||
];
|
|
||||||
var entryId = entry.querySelector('id')?.innerHtml;
|
|
||||||
var version =
|
|
||||||
entryId == null ? null : Uri.parse(entryId).pathSegments.last;
|
|
||||||
var releaseDateString = entry.querySelector('updated')?.innerHtml;
|
|
||||||
DateTime? releaseDate = releaseDateString != null
|
|
||||||
? DateTime.parse(releaseDateString)
|
|
||||||
: null;
|
|
||||||
if (version == null) {
|
|
||||||
throw NoVersionError();
|
|
||||||
}
|
|
||||||
return APKDetails(version, getApkUrlsFromUrls(apkUrls),
|
|
||||||
GitHub().getAppNames(standardUrl),
|
|
||||||
releaseDate: releaseDate);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (apkDetailsList.isEmpty) {
|
|
||||||
throw NoReleasesError(note: tr('gitlabSourceNote'));
|
|
||||||
}
|
|
||||||
if (fallbackToOlderReleases) {
|
if (fallbackToOlderReleases) {
|
||||||
if (additionalSettings['trackOnly'] != true) {
|
if (additionalSettings['trackOnly'] != true) {
|
||||||
apkDetailsList =
|
apkDetailsList =
|
||||||
apkDetailsList.where((e) => e.apkUrls.isNotEmpty).toList();
|
apkDetailsList.where((e) => e.apkUrls.isNotEmpty).toList();
|
||||||
}
|
}
|
||||||
if (apkDetailsList.isEmpty) {
|
if (apkDetailsList.isEmpty) {
|
||||||
throw NoReleasesError(note: tr('gitlabSourceNote'));
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apkDetailsList.first;
|
return apkDetailsList.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
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/apps_provider.dart';
|
import 'package:obtainium/providers/apps_provider.dart';
|
||||||
@ -213,11 +213,11 @@ class HTML extends AppSource {
|
|||||||
// Given an HTTP response, grab some links according to the common additional settings
|
// Given an HTTP response, grab some links according to the common additional settings
|
||||||
// (those that apply to intermediate and final steps)
|
// (those that apply to intermediate and final steps)
|
||||||
Future<List<MapEntry<String, String>>> grabLinksCommon(
|
Future<List<MapEntry<String, String>>> grabLinksCommon(
|
||||||
Response res, Map<String, dynamic> additionalSettings) async {
|
Response res, Uri url, Map<String, dynamic> additionalSettings) async {
|
||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
List<MapEntry<String, String>> allLinks = html
|
List<MapEntry<String, String>> allLinks = html
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.map((element) => MapEntry(
|
.map((element) => MapEntry(
|
||||||
@ -226,13 +226,12 @@ class HTML extends AppSource {
|
|||||||
? element.text
|
? element.text
|
||||||
: (element.attributes['href'] ?? '').split('/').last))
|
: (element.attributes['href'] ?? '').split('/').last))
|
||||||
.where((element) => element.key.isNotEmpty)
|
.where((element) => element.key.isNotEmpty)
|
||||||
.map((e) =>
|
.map((e) => MapEntry(ensureAbsoluteUrl(e.key, url), e.value))
|
||||||
MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value))
|
|
||||||
.toList();
|
.toList();
|
||||||
if (allLinks.isEmpty) {
|
if (allLinks.isEmpty) {
|
||||||
allLinks = RegExp(
|
allLinks = RegExp(
|
||||||
r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
|
r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
|
||||||
.allMatches(res.body)
|
.allMatches(res.data)
|
||||||
.map((match) =>
|
.map((match) =>
|
||||||
MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
|
MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
|
||||||
.toList();
|
.toList();
|
||||||
@ -285,6 +284,7 @@ class HTML extends AppSource {
|
|||||||
for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) {
|
for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) {
|
||||||
var intLinks = await grabLinksCommon(
|
var intLinks = await grabLinksCommon(
|
||||||
await sourceRequest(currentUrl, additionalSettings),
|
await sourceRequest(currentUrl, additionalSettings),
|
||||||
|
Uri.parse(currentUrl),
|
||||||
additionalSettings['intermediateLink'][i]);
|
additionalSettings['intermediateLink'][i]);
|
||||||
if (intLinks.isEmpty) {
|
if (intLinks.isEmpty) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
@ -298,8 +298,9 @@ class HTML extends AppSource {
|
|||||||
if (additionalSettings['directAPKLink'] != true) {
|
if (additionalSettings['directAPKLink'] != true) {
|
||||||
Response res = await sourceRequest(currentUrl, additionalSettings);
|
Response res = await sourceRequest(currentUrl, additionalSettings);
|
||||||
versionExtractionWholePageString =
|
versionExtractionWholePageString =
|
||||||
res.body.split('\r\n').join('\n').split('\n').join('\\n');
|
res.data.split('\r\n').join('\n').split('\n').join('\\n');
|
||||||
links = await grabLinksCommon(res, additionalSettings);
|
links =
|
||||||
|
await grabLinksCommon(res, Uri.parse(currentUrl), additionalSettings);
|
||||||
links = filterApks(links, additionalSettings['apkFilterRegEx'],
|
links = filterApks(links, additionalSettings['apkFilterRegEx'],
|
||||||
additionalSettings['invertAPKFilter']);
|
additionalSettings['invertAPKFilter']);
|
||||||
if (links.isEmpty) {
|
if (links.isEmpty) {
|
||||||
@ -319,7 +320,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')));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:http/http.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';
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ class HuaweiAppGallery extends AppSource {
|
|||||||
{Map<String, dynamic> additionalSettings = const {}}) async {
|
{Map<String, dynamic> additionalSettings = const {}}) async {
|
||||||
String dlUrl = getDlUrl(standardUrl);
|
String dlUrl = getDlUrl(standardUrl);
|
||||||
Response res = await requestAppdlRedirect(dlUrl, additionalSettings);
|
Response res = await requestAppdlRedirect(dlUrl, additionalSettings);
|
||||||
return res.headers['location'] != null
|
return res.headers.map['location']?.isNotEmpty == true
|
||||||
? appIdFromRedirectDlUrl(res.headers['location']!)
|
? appIdFromRedirectDlUrl(res.headers.map['location']![0])
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +72,12 @@ class HuaweiAppGallery extends AppSource {
|
|||||||
if (res.headers['location'] == null) {
|
if (res.headers['location'] == null) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
String appId = appIdFromRedirectDlUrl(res.headers['location']!);
|
String appId = appIdFromRedirectDlUrl(res.headers.map['location']![0]);
|
||||||
var relDateStr =
|
var relDateStr = res.headers.map['location']?[0]
|
||||||
res.headers['location']?.split('?')[0].split('.').reversed.toList()[1];
|
.split('?')[0]
|
||||||
|
.split('.')
|
||||||
|
.reversed
|
||||||
|
.toList()[1];
|
||||||
var relDateStrAdj = relDateStr?.split('');
|
var relDateStrAdj = relDateStr?.split('');
|
||||||
var tempLen = relDateStrAdj?.length ?? 0;
|
var tempLen = relDateStrAdj?.length ?? 0;
|
||||||
var i = 2;
|
var i = 2;
|
||||||
|
@ -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']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart';
|
import 'package:dio/dio.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';
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class Jenkins extends AppSource {
|
|||||||
Response res = await sourceRequest(
|
Response res = await sourceRequest(
|
||||||
'$standardUrl/lastSuccessfulBuild/api/json', additionalSettings);
|
'$standardUrl/lastSuccessfulBuild/api/json', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var json = jsonDecode(res.body);
|
var json = jsonDecode(res.data);
|
||||||
var releaseDate = json['timestamp'] == null
|
var releaseDate = json['timestamp'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int);
|
: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/github.dart';
|
import 'package:obtainium/app_sources/github.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';
|
||||||
@ -33,7 +33,7 @@ class Mullvad extends AppSource {
|
|||||||
Response res = await sourceRequest(
|
Response res = await sourceRequest(
|
||||||
'$standardUrl/en/download/android', additionalSettings);
|
'$standardUrl/en/download/android', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var versions = parse(res.body)
|
var versions = parse(res.data)
|
||||||
.querySelectorAll('p')
|
.querySelectorAll('p')
|
||||||
.map((e) => e.innerHtml)
|
.map((e) => e.innerHtml)
|
||||||
.where((p) => p.contains('Latest version: '))
|
.where((p) => p.contains('Latest version: '))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.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';
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class NeutronCode extends AppSource {
|
|||||||
) async {
|
) async {
|
||||||
Response res = await sourceRequest(standardUrl, additionalSettings);
|
Response res = await sourceRequest(standardUrl, additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var http = parse(res.body);
|
var http = parse(res.data);
|
||||||
var name = http.querySelector('.pd-title')?.innerHtml;
|
var name = http.querySelector('.pd-title')?.innerHtml;
|
||||||
var filename = http.querySelector('.pd-filename .pd-float')?.innerHtml;
|
var filename = http.querySelector('.pd-filename .pd-float')?.innerHtml;
|
||||||
if (filename == null) {
|
if (filename == null) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart';
|
import 'package:dio/dio.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';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ class Signal extends AppSource {
|
|||||||
Response res = await sourceRequest(
|
Response res = await sourceRequest(
|
||||||
'https://updates.${hosts[0]}/android/latest.json', additionalSettings);
|
'https://updates.${hosts[0]}/android/latest.json', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var json = jsonDecode(res.body);
|
var json = jsonDecode(res.data);
|
||||||
String? apkUrl = json['url'];
|
String? apkUrl = json['url'];
|
||||||
List<String> apkUrls = apkUrl == null ? [] : [apkUrl];
|
List<String> apkUrls = apkUrl == null ? [] : [apkUrl];
|
||||||
String? version = json['versionName'];
|
String? version = json['versionName'];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.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';
|
||||||
|
|
||||||
@ -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.data);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/html.dart';
|
import 'package:obtainium/app_sources/html.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';
|
||||||
@ -39,6 +39,15 @@ class SourceHut extends AppSource {
|
|||||||
String standardUrl,
|
String standardUrl,
|
||||||
Map<String, dynamic> additionalSettings,
|
Map<String, dynamic> additionalSettings,
|
||||||
) async {
|
) async {
|
||||||
|
if (standardUrl.endsWith('/refs')) {
|
||||||
|
standardUrl = standardUrl
|
||||||
|
.split('/')
|
||||||
|
.reversed
|
||||||
|
.toList()
|
||||||
|
.sublist(1)
|
||||||
|
.reversed
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
Uri standardUri = Uri.parse(standardUrl);
|
Uri standardUri = Uri.parse(standardUrl);
|
||||||
String appName = standardUri.pathSegments.last;
|
String appName = standardUri.pathSegments.last;
|
||||||
bool fallbackToOlderReleases =
|
bool fallbackToOlderReleases =
|
||||||
@ -46,7 +55,7 @@ class SourceHut extends AppSource {
|
|||||||
Response res =
|
Response res =
|
||||||
await sourceRequest('$standardUrl/refs/rss.xml', additionalSettings);
|
await sourceRequest('$standardUrl/refs/rss.xml', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var parsedHtml = parse(res.body);
|
var parsedHtml = parse(res.data);
|
||||||
List<APKDetails> apkDetailsList = [];
|
List<APKDetails> apkDetailsList = [];
|
||||||
int ind = 0;
|
int ind = 0;
|
||||||
|
|
||||||
@ -76,7 +85,7 @@ class SourceHut extends AppSource {
|
|||||||
var res2 = await sourceRequest(releasePage, additionalSettings);
|
var res2 = await sourceRequest(releasePage, additionalSettings);
|
||||||
List<MapEntry<String, String>> apkUrls = [];
|
List<MapEntry<String, String>> apkUrls = [];
|
||||||
if (res2.statusCode == 200) {
|
if (res2.statusCode == 200) {
|
||||||
apkUrls = getApkUrlsFromUrls(parse(res2.body)
|
apkUrls = getApkUrlsFromUrls(parse(res2.data)
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.map((e) => e.attributes['href'] ?? '')
|
.map((e) => e.attributes['href'] ?? '')
|
||||||
.where((e) => e.toLowerCase().endsWith('.apk'))
|
.where((e) => e.toLowerCase().endsWith('.apk'))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
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';
|
||||||
@ -38,7 +38,7 @@ class SteamMobile extends AppSource {
|
|||||||
}
|
}
|
||||||
String apkInURLRegexPattern =
|
String apkInURLRegexPattern =
|
||||||
'/$apkNamePrefix-([0-9]+\\.)*[0-9]+\\.apk\$';
|
'/$apkNamePrefix-([0-9]+\\.)*[0-9]+\\.apk\$';
|
||||||
var links = parse(res.body)
|
var links = parse(res.data)
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.map((e) => e.attributes['href'] ?? '')
|
.map((e) => e.attributes['href'] ?? '')
|
||||||
.where((e) => RegExp('https://.*$apkInURLRegexPattern').hasMatch(e))
|
.where((e) => RegExp('https://.*$apkInURLRegexPattern').hasMatch(e))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
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/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ class TelegramApp extends AppSource {
|
|||||||
Response res =
|
Response res =
|
||||||
await sourceRequest('https://t.me/s/TAndroidAPK', additionalSettings);
|
await sourceRequest('https://t.me/s/TAndroidAPK', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var http = parse(res.body);
|
var http = parse(res.data);
|
||||||
var messages =
|
var messages =
|
||||||
http.querySelectorAll('.tgme_widget_message_text.js-message_text');
|
http.querySelectorAll('.tgme_widget_message_text.js-message_text');
|
||||||
var version = messages.isNotEmpty
|
var version = messages.isNotEmpty
|
||||||
|
@ -37,7 +37,7 @@ class Uptodown extends AppSource {
|
|||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
String? version = html.querySelector('div.version')?.innerHtml;
|
String? version = html.querySelector('div.version')?.innerHtml;
|
||||||
String? apkUrl =
|
String? apkUrl =
|
||||||
'${standardUrl.split('/').reversed.toList().sublist(1).reversed.join('/')}/post-download';
|
'${standardUrl.split('/').reversed.toList().sublist(1).reversed.join('/')}/post-download';
|
||||||
@ -94,7 +94,7 @@ class Uptodown extends AppSource {
|
|||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
var finalUrlKey =
|
var finalUrlKey =
|
||||||
html.querySelector('.post-download')?.attributes['data-url'];
|
html.querySelector('.post-download')?.attributes['data-url'];
|
||||||
if (finalUrlKey == null) {
|
if (finalUrlKey == null) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
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/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
|
import 'package:obtainium/main.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
class VLC extends AppSource {
|
class VLC extends AppSource {
|
||||||
@ -29,7 +30,7 @@ class VLC extends AppSource {
|
|||||||
String standardUrl, Map<String, dynamic> additionalSettings) async {
|
String standardUrl, Map<String, dynamic> additionalSettings) async {
|
||||||
Response res = await sourceRequest(dwUrlBase, additionalSettings);
|
Response res = await sourceRequest(dwUrlBase, additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var dwLinks = parse(res.body)
|
var dwLinks = parse(res.data)
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.where((element) => element.attributes['href'] != 'last/')
|
.where((element) => element.attributes['href'] != 'last/')
|
||||||
.map((e) => e.attributes['href']?.split('/')[0])
|
.map((e) => e.attributes['href']?.split('/')[0])
|
||||||
@ -49,11 +50,11 @@ class VLC extends AppSource {
|
|||||||
String standardUrl,
|
String standardUrl,
|
||||||
Map<String, dynamic> additionalSettings,
|
Map<String, dynamic> additionalSettings,
|
||||||
) async {
|
) async {
|
||||||
Response res = await get(
|
Response res =
|
||||||
Uri.parse('https://www.videolan.org/vlc/download-android.html'));
|
await dio.get('https://www.videolan.org/vlc/download-android.html');
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var dwUrlBase = 'get.videolan.org/vlc-android';
|
var dwUrlBase = 'get.videolan.org/vlc-android';
|
||||||
var dwLinks = parse(res.body)
|
var dwLinks = parse(res.data)
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
element.attributes['href']?.contains(dwUrlBase) ?? false)
|
element.attributes['href']?.contains(dwUrlBase) ?? false)
|
||||||
@ -84,14 +85,14 @@ class VLC extends AppSource {
|
|||||||
Response res = await sourceRequest(apkUrl, additionalSettings);
|
Response res = await sourceRequest(apkUrl, additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
String? apkUrl =
|
String? apkUrl =
|
||||||
parse(res.body).querySelector('#alt_link')?.attributes['href'];
|
parse(res.data).querySelector('#alt_link')?.attributes['href'];
|
||||||
if (apkUrl == null) {
|
if (apkUrl == null) {
|
||||||
throw NoAPKError();
|
throw NoAPKError();
|
||||||
}
|
}
|
||||||
return apkUrl;
|
return apkUrl;
|
||||||
} else if (res.statusCode == 500 &&
|
} else if (res.statusCode == 500 &&
|
||||||
res.body.toLowerCase().indexOf('mirror') > 0) {
|
res.data.toLowerCase().indexOf('mirror') > 0) {
|
||||||
var html = parse(res.body);
|
var html = parse(res.data);
|
||||||
var err = '';
|
var err = '';
|
||||||
html.body?.nodes.forEach((element) {
|
html.body?.nodes.forEach((element) {
|
||||||
if (element.text != null) {
|
if (element.text != null) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.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';
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class WhatsApp extends AppSource {
|
|||||||
Response res =
|
Response res =
|
||||||
await sourceRequest('$standardUrl/android', additionalSettings);
|
await sourceRequest('$standardUrl/android', additionalSettings);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var targetLinks = parse(res.body)
|
var targetLinks = parse(res.data)
|
||||||
.querySelectorAll('a')
|
.querySelectorAll('a')
|
||||||
.map((e) => e.attributes['href'] ?? '')
|
.map((e) => e.attributes['href'] ?? '')
|
||||||
.where((e) => e.isNotEmpty)
|
.where((e) => e.isNotEmpty)
|
||||||
|
@ -18,6 +18,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:easy_localization/src/easy_localization_controller.dart';
|
import 'package:easy_localization/src/easy_localization_controller.dart';
|
||||||
// ignore: implementation_imports
|
// ignore: implementation_imports
|
||||||
import 'package:easy_localization/src/localization.dart';
|
import 'package:easy_localization/src/localization.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
List<MapEntry<Locale, String>> supportedLocales = const [
|
List<MapEntry<Locale, String>> supportedLocales = const [
|
||||||
MapEntry(Locale('en'), 'English'),
|
MapEntry(Locale('en'), 'English'),
|
||||||
@ -38,6 +39,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
|
|||||||
MapEntry(Locale('nl'), 'Nederlands'),
|
MapEntry(Locale('nl'), 'Nederlands'),
|
||||||
MapEntry(Locale('vi'), 'Tiếng Việt'),
|
MapEntry(Locale('vi'), 'Tiếng Việt'),
|
||||||
MapEntry(Locale('tr'), 'Türkçe'),
|
MapEntry(Locale('tr'), 'Türkçe'),
|
||||||
|
MapEntry(Locale('uk'), 'Українська'),
|
||||||
];
|
];
|
||||||
const fallbackLocale = Locale('en');
|
const fallbackLocale = Locale('en');
|
||||||
const localeDir = 'assets/translations';
|
const localeDir = 'assets/translations';
|
||||||
@ -45,6 +47,9 @@ var fdroid = false;
|
|||||||
|
|
||||||
final globalNavigatorKey = GlobalKey<NavigatorState>();
|
final globalNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
final dio = Dio(BaseOptions(
|
||||||
|
responseType: ResponseType.plain, receiveDataWhenStatusError: true));
|
||||||
|
|
||||||
Future<void> loadTranslations() async {
|
Future<void> loadTranslations() async {
|
||||||
// See easy_localization/issues/210
|
// See easy_localization/issues/210
|
||||||
await EasyLocalizationController.initEasyLocation();
|
await EasyLocalizationController.initEasyLocation();
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/github.dart';
|
import 'package:obtainium/app_sources/github.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
|
import 'package:obtainium/main.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
class GitHubStars implements MassAppUrlSource {
|
class GitHubStars implements MassAppUrlSource {
|
||||||
@ -15,13 +16,12 @@ class GitHubStars implements MassAppUrlSource {
|
|||||||
|
|
||||||
Future<Map<String, List<String>>> getOnePageOfUserStarredUrlsWithDescriptions(
|
Future<Map<String, List<String>>> getOnePageOfUserStarredUrlsWithDescriptions(
|
||||||
String username, int page) async {
|
String username, int page) async {
|
||||||
Response res = await get(
|
Response res = await dio.get(
|
||||||
Uri.parse(
|
'https://api.github.com/users/$username/starred?per_page=100&page=$page',
|
||||||
'https://api.github.com/users/$username/starred?per_page=100&page=$page'),
|
options: Options(headers: await GitHub().getRequestHeaders({})));
|
||||||
headers: await GitHub().getRequestHeaders({}));
|
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
Map<String, List<String>> urlsWithDescriptions = {};
|
Map<String, List<String>> urlsWithDescriptions = {};
|
||||||
for (var e in (jsonDecode(res.body) as List<dynamic>)) {
|
for (var e in (jsonDecode(res.data) as List<dynamic>)) {
|
||||||
urlsWithDescriptions.addAll({
|
urlsWithDescriptions.addAll({
|
||||||
e['html_url'] as String: [
|
e['html_url'] as String: [
|
||||||
e['full_name'] as String,
|
e['full_name'] as String,
|
||||||
|
@ -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))
|
||||||
],
|
],
|
||||||
@ -530,7 +518,20 @@ class AddAppPageState extends State<AddAppPage> {
|
|||||||
? TextDecoration.underline
|
? TextDecoration.underline
|
||||||
: TextDecoration.none),
|
: TextDecoration.none),
|
||||||
))),
|
))),
|
||||||
)
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${tr('note')}:',
|
||||||
|
style:
|
||||||
|
const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 4,
|
||||||
|
),
|
||||||
|
Text(tr('selfHostedNote',
|
||||||
|
args: [tr('overrideSource')])),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -564,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(
|
||||||
|
@ -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,
|
||||||
@ -205,6 +209,12 @@ class _AppPageState extends State<AppPage> {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context).textTheme.displayLarge,
|
style: Theme.of(context).textTheme.displayLarge,
|
||||||
),
|
),
|
||||||
|
Text(tr('byX', args: [app?.app.author ?? tr('unknown')]),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (app?.app.url != null) {
|
if (app?.app.url != null) {
|
||||||
@ -219,15 +229,12 @@ class _AppPageState extends State<AppPage> {
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
tr('byX', args: [app?.app.author ?? tr('unknown')]),
|
app?.app.url ?? '',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context).textTheme.headlineMedium!.copyWith(
|
style: Theme.of(context).textTheme.labelSmall!.copyWith(
|
||||||
decoration: TextDecoration.underline,
|
decoration: TextDecoration.underline,
|
||||||
fontStyle: FontStyle.italic),
|
fontStyle: FontStyle.italic),
|
||||||
)),
|
)),
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Text(
|
Text(
|
||||||
app?.app.id ?? '',
|
app?.app.id ?? '',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -358,6 +358,16 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
String? changesUrl =
|
String? changesUrl =
|
||||||
appSource.changeLogPageFromStandardUrl(listedApps[appIndex].app.url);
|
appSource.changeLogPageFromStandardUrl(listedApps[appIndex].app.url);
|
||||||
String? changeLog = listedApps[appIndex].app.changeLog;
|
String? changeLog = listedApps[appIndex].app.changeLog;
|
||||||
|
if (changeLog?.split('\n').length == 1) {
|
||||||
|
if (RegExp(
|
||||||
|
'(http|ftp|https)://([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?')
|
||||||
|
.hasMatch(changeLog!)) {
|
||||||
|
if (changesUrl == null) {
|
||||||
|
changesUrl = changeLog;
|
||||||
|
changeLog = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return (changeLog == null && changesUrl == null)
|
return (changeLog == null && changesUrl == null)
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
@ -1028,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
|
||||||
: () {
|
: () {
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,15 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
import 'package:android_intent_plus/flag.dart';
|
import 'package:android_intent_plus/flag.dart';
|
||||||
import 'package:android_package_installer/android_package_installer.dart';
|
import 'package:android_package_installer/android_package_installer.dart';
|
||||||
import 'package:android_package_manager/android_package_manager.dart';
|
import 'package:android_package_manager/android_package_manager.dart';
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
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';
|
||||||
@ -28,7 +29,6 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:flutter_fgbg/flutter_fgbg.dart';
|
import 'package:flutter_fgbg/flutter_fgbg.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:android_intent_plus/android_intent.dart';
|
import 'package:android_intent_plus/android_intent.dart';
|
||||||
import 'package:flutter_archive/flutter_archive.dart';
|
import 'package:flutter_archive/flutter_archive.dart';
|
||||||
import 'package:shared_storage/shared_storage.dart' as saf;
|
import 'package:shared_storage/shared_storage.dart' as saf;
|
||||||
@ -146,10 +146,10 @@ Future<File> downloadFileWithRetry(
|
|||||||
Map<String, String>? headers,
|
Map<String, String>? headers,
|
||||||
int retries = 3}) async {
|
int retries = 3}) async {
|
||||||
try {
|
try {
|
||||||
return await downloadFile(url, fileNameNoExt, onProgress, destDir,
|
return await downloadApk(url, fileNameNoExt, onProgress, destDir,
|
||||||
useExisting: useExisting, headers: headers);
|
useExisting: useExisting, headers: headers);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (retries > 0 && e is ClientException) {
|
if (retries > 0 && e is DioException) {
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
await Future.delayed(const Duration(seconds: 5));
|
||||||
return await downloadFileWithRetry(
|
return await downloadFileWithRetry(
|
||||||
url, fileNameNoExt, onProgress, destDir,
|
url, fileNameNoExt, onProgress, destDir,
|
||||||
@ -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 {
|
||||||
@ -183,9 +183,162 @@ Future<String> checkPartialDownloadHashDynamc(String url,
|
|||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<File> downloadApk(
|
||||||
|
String url, String fileNameNoExt, Function? onProgress, String destDir,
|
||||||
|
{bool useExisting = true, Map<String, String>? headers}) async {
|
||||||
|
var resHeaders = await getHeaders(url, headers: headers);
|
||||||
|
|
||||||
|
String ext = resHeaders['content-disposition']?.split('.').last ?? 'apk';
|
||||||
|
if (ext.endsWith('"') || ext.endsWith("other")) {
|
||||||
|
ext = ext.substring(0, ext.length - 1);
|
||||||
|
}
|
||||||
|
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') {
|
||||||
|
ext = 'apk';
|
||||||
|
}
|
||||||
|
File file = File('$destDir/$fileNameNoExt.$ext');
|
||||||
|
|
||||||
|
final contentLength = await getContentLengthIfRangeSupported(resHeaders);
|
||||||
|
|
||||||
|
if (useExisting && file.existsSync()) {
|
||||||
|
var length = file.lengthSync();
|
||||||
|
if (contentLength == null) {
|
||||||
|
return file;
|
||||||
|
} else {
|
||||||
|
if (length == contentLength) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
if (length > contentLength) {
|
||||||
|
useExisting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double progress = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (contentLength == null) {
|
||||||
|
Response response = await dio.download(
|
||||||
|
url,
|
||||||
|
file.path,
|
||||||
|
options: Options(headers: headers),
|
||||||
|
onReceiveProgress: (count, total) {
|
||||||
|
progress = (total > 0 ? count / total * 100 : 30);
|
||||||
|
if (onProgress != null) {
|
||||||
|
onProgress(progress);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if ((response.statusCode ?? 200) < 200 ||
|
||||||
|
(response.statusCode ?? 200) > 299) {
|
||||||
|
throw response.statusMessage ?? tr('unexpectedError');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var targetFileLength =
|
||||||
|
useExisting && file.existsSync() ? file.lengthSync() : null;
|
||||||
|
int bufferSize = 1024 * 1024; // 1 Megabyte
|
||||||
|
final sink = file.openWrite(
|
||||||
|
mode: useExisting ? FileMode.writeOnlyAppend : FileMode.writeOnly,
|
||||||
|
);
|
||||||
|
int rangeStart = targetFileLength ?? 0;
|
||||||
|
int rangeEnd = min(
|
||||||
|
rangeStart + bufferSize - 1,
|
||||||
|
contentLength - 1,
|
||||||
|
);
|
||||||
|
if (onProgress != null) {
|
||||||
|
progress = ((rangeStart / contentLength) * 100);
|
||||||
|
onProgress(progress);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
var headersCurrent = headers ?? {};
|
||||||
|
headersCurrent['range'] = 'bytes=$rangeStart-$rangeEnd';
|
||||||
|
Response response = await dio.get(
|
||||||
|
url,
|
||||||
|
onReceiveProgress: (count, total) {
|
||||||
|
if (onProgress != null) {
|
||||||
|
final newProgress =
|
||||||
|
(((rangeStart + count) / contentLength) * 100);
|
||||||
|
if (newProgress != progress) {
|
||||||
|
progress = newProgress;
|
||||||
|
onProgress(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
headers: headersCurrent,
|
||||||
|
responseType: ResponseType.bytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((response.statusCode ?? 200) < 200 ||
|
||||||
|
(response.statusCode ?? 200) > 299) {
|
||||||
|
throw response.statusMessage ?? tr('unexpectedError');
|
||||||
|
}
|
||||||
|
|
||||||
|
final Uint8List data = response.data;
|
||||||
|
sink.add(data);
|
||||||
|
if (rangeEnd == contentLength - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rangeStart = rangeEnd + 1;
|
||||||
|
rangeEnd = min(
|
||||||
|
rangeStart + bufferSize - 1,
|
||||||
|
contentLength - 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await sink.flush();
|
||||||
|
await sink.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (onProgress != null) {
|
||||||
|
onProgress(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int?> getContentLengthIfRangeSupported(
|
||||||
|
Map<String, String> headers) async {
|
||||||
|
try {
|
||||||
|
int? contentLength;
|
||||||
|
{
|
||||||
|
var contentLengthHeaderValue = headers['content-length'];
|
||||||
|
if (contentLengthHeaderValue?.isNotEmpty == true) {
|
||||||
|
contentLength = int.tryParse(contentLengthHeaderValue!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool rangeFeatureEnabled = false;
|
||||||
|
if (headers['accept-ranges']?.isNotEmpty == true) {
|
||||||
|
rangeFeatureEnabled =
|
||||||
|
headers['accept-ranges']!.trim().toLowerCase() == 'bytes';
|
||||||
|
}
|
||||||
|
if (!rangeFeatureEnabled) {
|
||||||
|
contentLength = null;
|
||||||
|
}
|
||||||
|
return contentLength;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> getHeaders(String url,
|
||||||
|
{Map<String, String>? headers}) async {
|
||||||
|
var req = http.Request('GET', Uri.parse(url));
|
||||||
|
if (headers != null) {
|
||||||
|
req.headers.addAll(headers);
|
||||||
|
}
|
||||||
|
var client = http.Client();
|
||||||
|
var response = await client.send(req);
|
||||||
|
if (response.statusCode < 200 || response.statusCode > 299) {
|
||||||
|
throw ObtainiumError(response.reasonPhrase ?? tr('unexpectedError'));
|
||||||
|
}
|
||||||
|
var returnHeaders = response.headers;
|
||||||
|
client.close();
|
||||||
|
return returnHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
|
Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
|
||||||
{Map<String, String>? headers}) async {
|
{Map<String, String>? headers}) async {
|
||||||
var req = Request('GET', Uri.parse(url));
|
var req = http.Request('GET', Uri.parse(url));
|
||||||
if (headers != null) {
|
if (headers != null) {
|
||||||
req.headers.addAll(headers);
|
req.headers.addAll(headers);
|
||||||
}
|
}
|
||||||
@ -199,58 +352,41 @@ Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
|
|||||||
return hashListOfLists(bytes);
|
return hashListOfLists(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File> downloadFile(
|
// Future<File> downloadFile(
|
||||||
String url, String fileNameNoExt, Function? onProgress, String destDir,
|
// String url, String fileNameNoExt, Function? onProgress, String destDir,
|
||||||
{bool useExisting = true, Map<String, String>? headers}) async {
|
// {bool useExisting = true, Map<String, String>? headers}) async {
|
||||||
var req = Request('GET', Uri.parse(url));
|
// var resHead = await dio.head(url);
|
||||||
if (headers != null) {
|
// String ext =
|
||||||
req.headers.addAll(headers);
|
// resHead.headers.map['content-disposition']?[0].split('.').last ?? 'apk';
|
||||||
}
|
// if (ext.endsWith('"') || ext.endsWith("other")) {
|
||||||
var client = http.Client();
|
// ext = ext.substring(0, ext.length - 1);
|
||||||
StreamedResponse response = await client.send(req);
|
// }
|
||||||
String ext =
|
// if (url.toLowerCase().endsWith('.apk') && ext != 'apk') {
|
||||||
response.headers['content-disposition']?.split('.').last ?? 'apk';
|
// ext = 'apk';
|
||||||
if (ext.endsWith('"') || ext.endsWith("other")) {
|
// }
|
||||||
ext = ext.substring(0, ext.length - 1);
|
// File downloadedFile = File('$destDir/$fileNameNoExt.$ext');
|
||||||
}
|
// if (!(downloadedFile.existsSync() && useExisting)) {
|
||||||
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') {
|
// double? progress;
|
||||||
ext = 'apk';
|
// var response = await dio.download(
|
||||||
}
|
// url,
|
||||||
File downloadedFile = File('$destDir/$fileNameNoExt.$ext');
|
// downloadedFile.path,
|
||||||
if (!(downloadedFile.existsSync() && useExisting)) {
|
// options: Options(headers: headers),
|
||||||
File tempDownloadedFile = File('${downloadedFile.path}.part');
|
// onReceiveProgress: (count, total) {
|
||||||
if (tempDownloadedFile.existsSync()) {
|
// progress = (total > 0 ? count / total * 100 : 30);
|
||||||
tempDownloadedFile.deleteSync(recursive: true);
|
// if (onProgress != null) {
|
||||||
}
|
// onProgress(progress);
|
||||||
var length = response.contentLength;
|
// }
|
||||||
var received = 0;
|
// },
|
||||||
double? progress;
|
// );
|
||||||
var sink = tempDownloadedFile.openWrite();
|
// if (onProgress != null) {
|
||||||
await response.stream.map((s) {
|
// onProgress(null);
|
||||||
received += s.length;
|
// }
|
||||||
progress = (length != null ? received / length * 100 : 30);
|
// if (response.statusCode != 200) {
|
||||||
if (onProgress != null) {
|
// throw response.statusMessage ?? tr('unexpectedError');
|
||||||
onProgress(progress);
|
// }
|
||||||
}
|
// }
|
||||||
return s;
|
// return downloadedFile;
|
||||||
}).pipe(sink);
|
// }
|
||||||
await sink.close();
|
|
||||||
progress = null;
|
|
||||||
if (onProgress != null) {
|
|
||||||
onProgress(progress);
|
|
||||||
}
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
tempDownloadedFile.deleteSync(recursive: true);
|
|
||||||
throw response.reasonPhrase ?? tr('unexpectedError');
|
|
||||||
}
|
|
||||||
if (tempDownloadedFile.existsSync()) {
|
|
||||||
tempDownloadedFile.renameSync(downloadedFile.path);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
return downloadedFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<PackageInfo?> getInstalledInfo(String? packageName,
|
Future<PackageInfo?> getInstalledInfo(String? packageName,
|
||||||
{bool printErr = true}) async {
|
{bool printErr = true}) async {
|
||||||
@ -532,9 +668,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 +853,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 +866,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 +909,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 +929,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);
|
||||||
}
|
}
|
||||||
@ -1611,7 +1757,7 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
|
|||||||
// Next task interval is based on the error with the longest retry time
|
// Next task interval is based on the error with the longest retry time
|
||||||
int minRetryIntervalForThisApp = err is RateLimitError
|
int minRetryIntervalForThisApp = err is RateLimitError
|
||||||
? (err.remainingMinutes * 60)
|
? (err.remainingMinutes * 60)
|
||||||
: e is ClientException
|
: e is DioException
|
||||||
? (15 * 60)
|
? (15 * 60)
|
||||||
: (toCheckApp.value + 1);
|
: (toCheckApp.value + 1);
|
||||||
if (minRetryIntervalForThisApp > maxRetryWaitSeconds) {
|
if (minRetryIntervalForThisApp > maxRetryWaitSeconds) {
|
||||||
|
@ -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) ||
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:obtainium/app_sources/apkmirror.dart';
|
import 'package:obtainium/app_sources/apkmirror.dart';
|
||||||
import 'package:obtainium/app_sources/apkpure.dart';
|
import 'package:obtainium/app_sources/apkpure.dart';
|
||||||
import 'package:obtainium/app_sources/aptoide.dart';
|
import 'package:obtainium/app_sources/aptoide.dart';
|
||||||
@ -31,6 +31,7 @@ import 'package:obtainium/app_sources/vlc.dart';
|
|||||||
import 'package:obtainium/app_sources/whatsapp.dart';
|
import 'package:obtainium/app_sources/whatsapp.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/main.dart';
|
||||||
import 'package:obtainium/mass_app_sources/githubstars.dart';
|
import 'package:obtainium/mass_app_sources/githubstars.dart';
|
||||||
import 'package:obtainium/providers/settings_provider.dart';
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
|
|
||||||
@ -442,16 +443,9 @@ abstract class AppSource {
|
|||||||
String url, Map<String, dynamic> additionalSettings,
|
String url, Map<String, dynamic> additionalSettings,
|
||||||
{bool followRedirects = true}) async {
|
{bool followRedirects = true}) async {
|
||||||
var requestHeaders = await getRequestHeaders(additionalSettings);
|
var requestHeaders = await getRequestHeaders(additionalSettings);
|
||||||
if (requestHeaders != null || followRedirects == false) {
|
return await dio.get(url,
|
||||||
var req = Request('GET', Uri.parse(url));
|
options:
|
||||||
req.followRedirects = followRedirects;
|
Options(headers: requestHeaders, followRedirects: followRedirects));
|
||||||
if (requestHeaders != null) {
|
|
||||||
req.headers.addAll(requestHeaders);
|
|
||||||
}
|
|
||||||
return Response.fromStream(await Client().send(req));
|
|
||||||
} else {
|
|
||||||
return get(Uri.parse(url));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String sourceSpecificStandardizeURL(String url) {
|
String sourceSpecificStandardizeURL(String url) {
|
||||||
@ -618,10 +612,10 @@ abstract class AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObtainiumError getObtainiumHttpError(Response res) {
|
ObtainiumError getObtainiumHttpError(Response res) {
|
||||||
return ObtainiumError((res.reasonPhrase != null &&
|
return ObtainiumError((res.statusMessage != null &&
|
||||||
res.reasonPhrase != null &&
|
res.statusMessage != null &&
|
||||||
res.reasonPhrase!.isNotEmpty)
|
res.statusMessage!.isNotEmpty)
|
||||||
? res.reasonPhrase!
|
? res.statusMessage!
|
||||||
: tr('errorWithHttpStatusCode', args: [res.statusCode.toString()]));
|
: tr('errorWithHttpStatusCode', args: [res.statusCode.toString()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,7 +813,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 +823,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 +881,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 +907,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) {
|
||||||
|
196
pubspec.lock
196
pubspec.lock
@ -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:
|
||||||
@ -38,10 +38,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: app_links
|
name: app_links
|
||||||
sha256: "4e392b5eba997df356ca6021f28431ce1cfeb16758699553a94b13add874a3bb"
|
sha256: "3ced568a5d9e309e99af71285666f1f3117bddd0bd5b3317979dccc1a40cada4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.0"
|
version: "3.5.1"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -70,10 +70,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: background_fetch
|
name: background_fetch
|
||||||
sha256: "34550cf9b383e5a1844e7d22119aa500508c7df9421fa967c9fb4430d6cb2878"
|
sha256: eb3af263d390d7e68ecb90f2ae984d2bfd96dceb4c7b4f72418dd5383b49de0a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.4"
|
||||||
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:
|
||||||
@ -202,22 +202,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
|
dio:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dio
|
||||||
|
sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.4.1"
|
||||||
dynamic_color:
|
dynamic_color:
|
||||||
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 +246,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:
|
||||||
@ -254,10 +262,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6"
|
sha256: caa6bc229eab3e32eb2f37b53a5f9d22a6981474afd210c512a7546c1e1a04f6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.2.0"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -307,10 +315,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications
|
name: flutter_local_notifications
|
||||||
sha256: c18f1de98fe0bb9dd5ba91e1330d4febc8b6a7de6aae3ffe475ef423723e72f3
|
sha256: "55b9b229307a10974b26296ff29f2e132256ba4bd74266939118eaefa941cb00"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "16.3.2"
|
version: "16.3.3"
|
||||||
flutter_local_notifications_linux:
|
flutter_local_notifications_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -336,10 +344,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: "30088ce826b5b9cfbf9e8bece34c716c8a59fa54461dcae1e4ac01a94639e762"
|
sha256: cb44f7831b23a6bdd0f501718b0d2e8045cbc625a15f668af37ddb80314821db
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.18+3"
|
version: "0.6.21"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -394,10 +402,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 +418,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 +446,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:
|
||||||
@ -450,34 +482,34 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90"
|
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.1"
|
version: "7.2.2"
|
||||||
matcher:
|
matcher:
|
||||||
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 +538,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 +594,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 +626,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 +674,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 +738,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 +754,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
|
||||||
@ -751,18 +783,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite
|
name: sqflite
|
||||||
sha256: c2c32eb0c74021d987336522acc3b6bf0082fbd0c540c36a9cf4ddb8ba891ddc
|
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
sqflite_common:
|
sqflite_common:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6
|
sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0+2"
|
version: "2.5.3"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -831,26 +863,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 +903,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 +939,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: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.5.1"
|
||||||
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,18 +983,18 @@ 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:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.0"
|
version: "5.3.0"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -988,5 +1028,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"
|
||||||
|
@ -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.0+250 # When changing this, update the tag in main() accordingly
|
version: 1.0.5+2255 # 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'
|
||||||
@ -68,6 +68,7 @@ dependencies:
|
|||||||
crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
app_links: ^3.5.0
|
app_links: ^3.5.0
|
||||||
background_fetch: ^1.2.1
|
background_fetch: ^1.2.1
|
||||||
|
dio: ^5.4.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user