mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
feat(settings): filter pre-releases and add version compare
Filter out pre-release GitHub releases (beta,, rc, preview, dev, canary, nightly) when resolving the latest app version and validate release names using semver. Sort stable releases by creation date and return the most recent stable release name. Add isVersionOutdated(current, latest) to compare coerced semver versions safely, handling invalid formats with a warning. Move version comparison logic from the settings component to the SettingsService and use the new helper to determine if the installed app is outdated. This prevents false positives from pre-release tags and improves version parsing robustness.
This commit is contained in:
1 parent
c34bdf73e1
commit
80fa80ff09
2 files changed
+73
-10
No files matched your search
@@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { StorageMap } from '@ngx-pwa/local-storage';
|
||||
import { catchError, map, Observable } from 'rxjs';
|
||||
import * as semver from 'semver';
|
||||
import { STORE_KEY, Theme } from 'shared-interfaces';
|
||||
|
||||
@Injectable({
|
||||
@@ -52,6 +53,7 @@ export class SettingsService {
|
||||
|
||||
/**
|
||||
* Returns the version of the released app
|
||||
* Filters out pre-release versions (beta, alpha, rc)
|
||||
*/
|
||||
getAppVersion() {
|
||||
return this.http
|
||||
@@ -59,14 +61,48 @@ export class SettingsService {
|
||||
'https://api.github.com/repos/4gray/iptvnator/releases'
|
||||
)
|
||||
.pipe(
|
||||
map(
|
||||
(response) =>
|
||||
response.sort(
|
||||
(a, b) =>
|
||||
new Date(b.created_at).getTime() -
|
||||
new Date(a.created_at).getTime()
|
||||
)[0]
|
||||
),
|
||||
map((response) => {
|
||||
// Filter out pre-release versions (beta, alpha, rc, etc.)
|
||||
const stableReleases = response.filter((release) => {
|
||||
const releaseName = release.name.toLowerCase();
|
||||
|
||||
// Check for beta/alpha/rc keywords in the release name
|
||||
const prereleaseKeywords = [
|
||||
'beta',
|
||||
'alpha',
|
||||
'rc',
|
||||
'preview',
|
||||
'dev',
|
||||
'canary',
|
||||
'nightly',
|
||||
];
|
||||
const hasPrereleaseKeyword = prereleaseKeywords.some(
|
||||
(keyword) => releaseName.includes(keyword)
|
||||
);
|
||||
|
||||
if (hasPrereleaseKeyword) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate version format
|
||||
const version = semver.valid(
|
||||
semver.coerce(release.name)
|
||||
);
|
||||
if (!version) return false;
|
||||
|
||||
// Check if version has prerelease tags in semver format
|
||||
return !semver.prerelease(release.name);
|
||||
});
|
||||
|
||||
// Sort stable releases by creation date
|
||||
const sortedReleases = stableReleases.sort(
|
||||
(a, b) =>
|
||||
new Date(b.created_at).getTime() -
|
||||
new Date(a.created_at).getTime()
|
||||
);
|
||||
|
||||
return sortedReleases[0];
|
||||
}),
|
||||
map((response) => response.name),
|
||||
catchError((err) => {
|
||||
console.error(err);
|
||||
@@ -74,4 +110,29 @@ export class SettingsService {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares current version with latest version
|
||||
* @param currentVersion current version of the app
|
||||
* @param latestVersion latest stable version from GitHub
|
||||
* @returns true if current version is outdated
|
||||
*/
|
||||
isVersionOutdated(
|
||||
currentVersion: string,
|
||||
latestVersion: string
|
||||
): boolean {
|
||||
// Clean and coerce versions to handle invalid formats
|
||||
const cleanCurrent = semver.coerce(currentVersion);
|
||||
const cleanLatest = semver.coerce(latestVersion);
|
||||
|
||||
if (!cleanCurrent || !cleanLatest) {
|
||||
console.warn('Invalid version format:', {
|
||||
currentVersion,
|
||||
latestVersion,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return semver.lt(cleanCurrent, cleanLatest);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import { DialogService } from 'components';
|
||||
import * as PlaylistActions from 'm3u-state';
|
||||
import { selectIsEpgAvailable } from 'm3u-state';
|
||||
import { take } from 'rxjs';
|
||||
import * as semver from 'semver';
|
||||
import { DataService, EpgService, PlaylistsService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
@@ -242,7 +241,10 @@ export class SettingsComponent implements OnInit {
|
||||
*/
|
||||
isCurrentVersionOutdated(latestVersion: string): boolean {
|
||||
this.version = this.dataService.getAppVersion();
|
||||
return semver.lt(this.version, latestVersion);
|
||||
return this.settingsService.isVersionOutdated(
|
||||
this.version,
|
||||
latestVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user