Better sort options for GitHub releases (#2144)

This commit is contained in:
Imran Remtulla
2025-03-07 18:05:45 -05:00
parent 044bd7f8a0
commit 5e6e3f457c
27 changed files with 150 additions and 44 deletions

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější",
"refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením",
"tencentAppStore": "Tencent App Store",
"name": "Název",
"smartname": "Název (Smart)",
"sortMethod": "Metoda třídění",
"removeAppQuestion": {
"one": "Odstranit Apku?",
"other": "Odstranit Apky?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Forbliv én version bagud den seneste",
"refreshBeforeDownload": "Opdater app-detaljer før download",
"tencentAppStore": "Tencent App Store",
"name": "Navn",
"smartname": "Navn (Smart)",
"sortMethod": "Sorteringsmetode",
"removeAppQuestion": {
"one": "Fjern app?",
"other": "Fjern apps?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben",
"refreshBeforeDownload": "App-Details vor dem Download aktualisieren",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sortierverfahren",
"removeAppQuestion": {
"one": "App entfernen?",
"other": "Apps entfernen?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Forigi la aplikaĵon?",
"other": "Forigi la aplikaĵojn?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Remove App?",
"other": "Remove Apps?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Mantenerse una versión por detrás de la última",
"refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla",
"tencentAppStore": "Tencent App Store",
"name": "Nombre",
"smartname": "Nombre (Smart)",
"sortMethod": "Método de clasificación",
"removeAppQuestion": {
"one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "یک نسخه از آخرین نسخه پشت سر بگذارید",
"refreshBeforeDownload": "قبل از دانلود، جزئیات برنامه را بازخوانی کنید",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Rester une version en arrière de la dernière",
"refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger",
"tencentAppStore": "Tencent App Store",
"name": "Nom",
"smartname": "Nom (Smart)",
"sortMethod": "Méthode de tri",
"removeAppQuestion": {
"one": "Supprimer l'application ?",
"other": "Supprimer les applications ?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött",
"refreshBeforeDownload": "Az alkalmazás adatainak frissítése a letöltés előtt",
"tencentAppStore": "Tencent Appstore",
"name": "Név",
"smartname": "Név (Smart)",
"sortMethod": "Rendezési módszer",
"removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru",
"refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh",
"tencentAppStore": "Tencent App Store",
"name": "Nama",
"smartname": "Nama (Cerdas)",
"sortMethod": "Metode Penyortiran",
"removeAppQuestion": {
"one": "Hapus aplikasi?",
"other": "Hapus aplikasi?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente",
"refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download",
"tencentAppStore": "Tencent App Store",
"name": "Nome",
"smartname": "Nome (intelligente)",
"sortMethod": "Metodo di ordinamento",
"removeAppQuestion": {
"one": "Rimuovere l'app?",
"other": "Rimuovere le app?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "最新のバージョンから1つ前のものを使用する",
"refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "名前(スマート)",
"sortMethod": "ソート方法",
"removeAppQuestion": {
"one": "アプリを削除しますか?",
"other": "アプリを削除しますか?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "최신 버전보다 한 버전 뒤에 머무르기",
"refreshBeforeDownload": "다운로드 전에 앱 세부 정보 새로 고침",
"tencentAppStore": "텐센트 앱 스토어",
"name": "이름",
"smartname": "이름(스마트)",
"sortMethod": "정렬 방법",
"removeAppQuestion": {
"one": "앱을 제거하시겠습니까?",
"other": "앱을 제거하시겠습니까?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Blijf een versie achter op de nieuwste",
"refreshBeforeDownload": "Vernieuw app details voor download",
"tencentAppStore": "Tencent App Store",
"name": "Naam",
"smartname": "Naam (Slim)",
"sortMethod": "Sorteermethode",
"removeAppQuestion": {
"one": "App verwijderen?",
"other": "Apps verwijderen?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą",
"refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem",
"tencentAppStore": "Tencent App Store",
"name": "Nazwa",
"smartname": "Nazwa (Smart)",
"sortMethod": "Metoda sortowania",
"removeAppQuestion": {
"one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?",

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Manter-se uma versão atrás da mais recente",
"refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência",
"tencentAppStore": "Tencent App Store",
"name": "Nome",
"smartname": "Nome (Smart)",
"sortMethod": "Método de ordenação",
"removeAppQuestion": {
"one": "Remover aplicativo?",
"other": "Remover aplicativos?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Не отставайте от последней версии",
"refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой",
"tencentAppStore": "Tencent App Store",
"name": "Имя",
"smartname": "Имя (умное)",
"sortMethod": "Метод сортировки",
"removeAppQuestion": {
"one": "Удалить приложение?",
"other": "Удалить приложения?"

View File

@ -13,7 +13,10 @@ const neverAutoTranslate = {
obtainiumExportHyphenatedLowercase: ['*'],
theme: ['de'],
appId: ['de'],
placeholder: ['pl']
placeholder: ['pl'],
importExport: ['fr'],
url: ['fr'],
tencentAppStore: ['*']
}
const translateText = async (text, targetLang, authKey) => {
@ -76,40 +79,49 @@ const main = async () => {
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])
try {
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) => {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, Math.random() * 1000); // Try to avoid rate limit
})
const response = await translateText(str, lang, deeplAPIKey)
if (response.translations) {
return response.translations[0].text
} else {
throw JSON.stringify(response)
}
}
} catch (e) {
if (typeof e == 'string') {
console.log(`${reportLine} :::: ${e}`)
} else {
throw e
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)
}
} else {
console.log(reportLine)
}
}
} catch (err) {
console.error(err)
}
}
fs.writeFileSync(file, `${JSON.stringify(thisTranslation, null, ' ')}\n`)

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Håll dig en version bakom den senaste",
"refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning",
"tencentAppStore": "Tencent App Store",
"name": "Namn",
"smartname": "Namn (Smart)",
"sortMethod": "Sorteringsmetod",
"removeAppQuestion": {
"one": "Ta Bort App?",
"other": "Ta Bort Appar?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın",
"refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin",
"tencentAppStore": "Tencent App Store",
"name": "İsim",
"smartname": "İsim (Akıllı)",
"sortMethod": "Sıralama Yöntemi",
"removeAppQuestion": {
"one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою",
"refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням",
"tencentAppStore": "Tencent App Store",
"name": "Ім'я",
"smartname": "Ім'я (Smart)",
"sortMethod": "Метод сортування",
"removeAppQuestion": {
"one": "Видалити застосунок?",
"other": "Видалити застосунки?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "Tencent App Store",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"tencentAppStore": "騰訊應用寶",
"name": "Name",
"smartname": "Name (Smart)",
"sortMethod": "Sort Method",
"removeAppQuestion": {
"one": "移除應用程式?",
"other": "移除應用程式?"

View File

@ -319,6 +319,9 @@
"stayOneVersionBehind": "比最新版本晚一个版本",
"refreshBeforeDownload": "下载前刷新应用程序详细信息",
"tencentAppStore": "腾讯应用宝",
"name": "名称",
"smartname": "姓名(智能)",
"sortMethod": "排序方法",
"removeAppQuestion": {
"one": "是否删除应用?",
"other": "是否删除应用?"

View File

@ -75,8 +75,18 @@ class GitHub extends AppSource {
],
[GeneratedFormSwitch('verifyLatestTag', label: tr('verifyLatestTag'))],
[
GeneratedFormSwitch('dontSortReleasesList',
label: tr('dontSortReleasesList'))
GeneratedFormDropdown(
'sortMethodChoice',
[
MapEntry('date', tr('releaseDate')),
MapEntry('smartname', tr('smartname')),
MapEntry('none', tr('none')),
MapEntry('smartname-datefallback',
'${tr('smartname')} x ${tr('releaseDate')}'),
MapEntry('name', tr('name')),
],
label: tr('sortMethod'),
defaultValue: 'date')
],
[
GeneratedFormSwitch('useLatestAssetDateAsReleaseDate',
@ -244,10 +254,10 @@ class GitHub extends AppSource {
? additionalSettings['filterReleaseNotesByRegEx']
: null;
bool verifyLatestTag = additionalSettings['verifyLatestTag'] == true;
bool dontSortReleasesList =
additionalSettings['dontSortReleasesList'] == true;
bool useLatestAssetDateAsReleaseDate =
additionalSettings['useLatestAssetDateAsReleaseDate'] == true;
String sortMethod =
additionalSettings['sortMethodChoice'] ?? 'smartname-datefallback';
dynamic latestRelease;
if (verifyLatestTag) {
var temp = requestUrl.split('?');
@ -316,7 +326,7 @@ class GitHub extends AppSource {
? getPublishDateFromRelease(rel)
: getNewestAssetDateFromRelease(rel);
if (dontSortReleasesList) {
if (sortMethod == 'none') {
releases = releases.reversed.toList();
} else {
releases.sort((a, b) {
@ -330,22 +340,30 @@ class GitHub extends AppSource {
} else {
var nameA = a['tag_name'] ?? a['name'];
var nameB = b['tag_name'] ?? b['name'];
var stdFormats = findStandardFormatsForVersion(nameA, true)
.intersection(findStandardFormatsForVersion(nameB, true));
if (stdFormats.isNotEmpty) {
var reg = RegExp(stdFormats.first);
var matchA = reg.firstMatch(nameA);
var matchB = reg.firstMatch(nameB);
return compareAlphaNumeric(
(nameA as String).substring(matchA!.start, matchA.end),
(nameB as String).substring(matchB!.start, matchB.end));
} else {
var stdFormats = findStandardFormatsForVersion(nameA, false)
.intersection(findStandardFormatsForVersion(nameB, false));
if (sortMethod == 'date' ||
(sortMethod == 'smartname-datefallback' &&
stdFormats.isEmpty)) {
return (getReleaseDateFromRelease(
a, useLatestAssetDateAsReleaseDate) ??
DateTime(1))
.compareTo(getReleaseDateFromRelease(
b, useLatestAssetDateAsReleaseDate) ??
DateTime(0));
} else {
if (sortMethod != 'name' && stdFormats.isNotEmpty) {
var reg = RegExp(stdFormats.last);
var matchA = reg.firstMatch(nameA);
var matchB = reg.firstMatch(nameB);
return compareAlphaNumeric(
(nameA as String).substring(matchA!.start, matchA.end),
(nameB as String).substring(matchB!.start, matchB.end));
} else {
// 'name'
return compareAlphaNumeric(
(nameA as String), (nameB as String));
}
}
}
});

View File

@ -152,6 +152,10 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
if (additionalSettings['autoApkFilterByArch'] == null) {
additionalSettings['autoApkFilterByArch'] = false;
}
// GitHub "don't sort" option to new dropdown format
if (additionalSettings['dontSortReleasesList'] == true) {
additionalSettings['sortMethodChoice'] = 'none';
}
if (source.runtimeType == HTML().runtimeType) {
// HTML key rename
if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) {