mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
* feat(updater): nightly builds and a stable/nightly update channel Every master push publishes its artifacts as a prerelease of 4gray/iptvnator-nightly instead of the rolling test-master draft, with a version of <next patch>-nightly.<commit date>.<run number> applied in every build job. Settings → About gains an Update channel switch; AppUpdateService re-points electron-updater per check (feed repository, allowPrerelease, channel name, allowDowngrade reset) and reads release notes from the repository the requested version belongs to. Channel switches are forward-only: a nightly build stays until a newer stable release exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(updater): compute the nightly version once and keep re-runs safe Review follow-ups: the nightly version is resolved by a leading job and handed to every build job, and the patch is bumped only when the base tag already exists so the release-cut window stays below the imminent release. A re-run never deletes a published nightly; only a draft left by a failed run is replaced. Typed update-status literals in the remaining specs carry the new channel fields. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(packaging): expect the nightly-version prerequisite in the build workflow graph Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
359 lines
16 KiB
HTML
359 lines
16 KiB
HTML
<section
|
|
class="settings-group"
|
|
id="about"
|
|
>
|
|
<header class="settings-group__header">
|
|
<div class="settings-group__header-icon">
|
|
<mat-icon>info</mat-icon>
|
|
</div>
|
|
<div class="settings-group__header-text">
|
|
<h3>{{ 'SETTINGS.ABOUT' | translate }}</h3>
|
|
<p>{{ 'SETTINGS.ABOUT_SUBTITLE' | translate }}</p>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="setting-item">
|
|
<div class="setting-item__meta">
|
|
<h4>{{ 'SETTINGS.VERSION' | translate }}</h4>
|
|
<p>{{ 'SETTINGS.VERSION_DESCRIPTION' | translate }}</p>
|
|
</div>
|
|
<div class="setting-item__control version-block">
|
|
<span data-test-id="app-version">
|
|
{{ version() }}
|
|
@if (buildCommitShort(); as commit) {
|
|
<span
|
|
class="build-commit"
|
|
data-test-id="app-build-commit"
|
|
[title]="buildCommit()"
|
|
>({{ commit }})</span
|
|
>
|
|
}
|
|
</span>
|
|
<small>{{ updateMessage() }}</small>
|
|
</div>
|
|
</div>
|
|
|
|
@if (isDesktop() && appUpdateStatus(); as updateStatus) {
|
|
<div class="setting-item setting-item--full-control app-update-panel">
|
|
<div class="setting-item__meta">
|
|
<h4>{{ 'SETTINGS.APP_UPDATE_TITLE' | translate }}</h4>
|
|
<p>{{ 'SETTINGS.APP_UPDATE_DESCRIPTION' | translate }}</p>
|
|
</div>
|
|
<div class="setting-item__control app-update-panel__control">
|
|
<div class="app-update-status" data-test-id="app-update-status">
|
|
<strong>
|
|
{{
|
|
appUpdateStatusLabelKey()
|
|
| translate
|
|
: {
|
|
version:
|
|
updateStatus.latestVersion ||
|
|
updateStatus.currentVersion,
|
|
}
|
|
}}
|
|
</strong>
|
|
@if (updateStatus.error) {
|
|
<span>{{ updateStatus.error }}</span>
|
|
}
|
|
@if (updateStatus.progress; as progress) {
|
|
<progress
|
|
[value]="progress.percent"
|
|
max="100"
|
|
data-test-id="app-update-progress"
|
|
></progress>
|
|
}
|
|
</div>
|
|
@if (canSelectUpdateChannel()) {
|
|
<div
|
|
class="app-update-channel"
|
|
[formGroup]="form()!"
|
|
data-test-id="app-update-channel"
|
|
>
|
|
<mat-form-field appearance="outline">
|
|
<mat-label>{{
|
|
'SETTINGS.APP_UPDATE_CHANNEL' | translate
|
|
}}</mat-label>
|
|
<mat-select
|
|
formControlName="updateChannel"
|
|
data-test-id="select-update-channel"
|
|
>
|
|
@for (
|
|
option of updateChannelOptions();
|
|
track option.value
|
|
) {
|
|
<mat-option
|
|
[value]="option.value"
|
|
[attr.data-test-id]="
|
|
'update-channel-' + option.value
|
|
"
|
|
>
|
|
{{ option.labelKey | translate }}
|
|
</mat-option>
|
|
}
|
|
</mat-select>
|
|
</mat-form-field>
|
|
<small class="app-update-channel__note">
|
|
{{
|
|
'SETTINGS.APP_UPDATE_CHANNEL_DESCRIPTION'
|
|
| translate
|
|
}}
|
|
</small>
|
|
@if (form()!.get('updateChannel')?.value === 'nightly') {
|
|
<small
|
|
class="app-update-channel__note"
|
|
data-test-id="app-update-channel-nightly-warning"
|
|
>
|
|
{{
|
|
'SETTINGS.APP_UPDATE_CHANNEL_NIGHTLY_WARNING'
|
|
| translate
|
|
}}
|
|
</small>
|
|
}
|
|
@if (isNightlyBuildOnStableChannel()) {
|
|
<small
|
|
class="app-update-channel__note"
|
|
data-test-id="app-update-nightly-on-stable-hint"
|
|
>
|
|
{{
|
|
'SETTINGS.APP_UPDATE_NIGHTLY_ON_STABLE_HINT'
|
|
| translate
|
|
}}
|
|
</small>
|
|
}
|
|
</div>
|
|
}
|
|
<div class="app-update-actions">
|
|
<button
|
|
mat-stroked-button
|
|
type="button"
|
|
(click)="checkForAppUpdate.emit()"
|
|
[disabled]="isAppUpdateBusy()"
|
|
data-test-id="app-update-check"
|
|
>
|
|
<mat-icon>sync</mat-icon>
|
|
{{ 'SETTINGS.APP_UPDATE_CHECK' | translate }}
|
|
</button>
|
|
@if (canDownloadAppUpdate()) {
|
|
<button
|
|
mat-flat-button
|
|
type="button"
|
|
(click)="downloadAppUpdate.emit()"
|
|
data-test-id="app-update-download"
|
|
>
|
|
<mat-icon>download</mat-icon>
|
|
{{ 'SETTINGS.APP_UPDATE_DOWNLOAD' | translate }}
|
|
</button>
|
|
}
|
|
@if (canOpenAppUpdateReleaseNotes()) {
|
|
<button
|
|
mat-stroked-button
|
|
type="button"
|
|
(click)="openAppUpdateReleaseNotes.emit()"
|
|
data-test-id="app-update-release-notes"
|
|
>
|
|
<mat-icon>article</mat-icon>
|
|
{{
|
|
'SETTINGS.APP_UPDATE_RELEASE_NOTES'
|
|
| translate
|
|
}}
|
|
</button>
|
|
}
|
|
@if (canInstallAppUpdate()) {
|
|
<button
|
|
mat-flat-button
|
|
type="button"
|
|
(click)="installAppUpdate.emit()"
|
|
data-test-id="app-update-install"
|
|
>
|
|
<mat-icon>restart_alt</mat-icon>
|
|
{{ 'SETTINGS.APP_UPDATE_INSTALL' | translate }}
|
|
</button>
|
|
}
|
|
@if (canOpenManualAppUpdate()) {
|
|
<button
|
|
mat-stroked-button
|
|
type="button"
|
|
(click)="openManualAppUpdate.emit()"
|
|
data-test-id="app-update-open-release"
|
|
>
|
|
<mat-icon>open_in_new</mat-icon>
|
|
{{ 'SETTINGS.APP_UPDATE_OPEN_RELEASE' | translate }}
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (isDesktop()) {
|
|
<div class="settings-note">
|
|
<strong>{{
|
|
'SETTINGS.EMBEDDED_MPV_NOTICE_TITLE' | translate
|
|
}}</strong>
|
|
<span>{{
|
|
'SETTINGS.EMBEDDED_MPV_NOTICE_DESCRIPTION' | translate
|
|
}}</span>
|
|
</div>
|
|
}
|
|
|
|
<div class="setting-item setting-item--full-control">
|
|
<div class="setting-item__meta">
|
|
<h4>{{ 'SETTINGS.TMDB_CREDITS' | translate }}</h4>
|
|
<p>{{ 'SETTINGS.TMDB_ATTRIBUTION' | translate }}</p>
|
|
<a
|
|
href="https://www.themoviedb.org"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
>
|
|
<img
|
|
src="assets/images/tmdb-logo.svg"
|
|
alt="TMDB"
|
|
style="height: 20px; margin-top: 8px"
|
|
/>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="setting-item setting-item--full-control">
|
|
<div class="setting-item__meta">
|
|
<h4>{{ 'SETTINGS.COMMUNITY' | translate }}</h4>
|
|
<p>{{ 'SETTINGS.COMMUNITY_DESCRIPTION' | translate }}</p>
|
|
</div>
|
|
<div class="setting-item__control">
|
|
<div class="link-cards">
|
|
<a
|
|
class="link-card link-card--github"
|
|
href="https://github.com/4gray/iptvnator"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
data-test-id="link-github"
|
|
>
|
|
<span class="link-card__glyph">
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
<path
|
|
fill="currentColor"
|
|
d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.6.112.793-.26.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.52 11.52 0 0 1 12 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.565 21.796 24 17.3 24 12c0-6.627-5.373-12-12-12z"
|
|
/>
|
|
</svg>
|
|
</span>
|
|
<span class="link-card__text">
|
|
<strong>GitHub</strong>
|
|
<span>{{
|
|
'SETTINGS.LINK_GITHUB_DESCRIPTION' | translate
|
|
}}</span>
|
|
</span>
|
|
<mat-icon class="link-card__arrow">arrow_outward</mat-icon>
|
|
</a>
|
|
<a
|
|
class="link-card link-card--blog"
|
|
href="https://4gray.github.io/iptvnator/"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
data-test-id="link-blog"
|
|
>
|
|
<span class="link-card__glyph">
|
|
<mat-icon>menu_book</mat-icon>
|
|
</span>
|
|
<span class="link-card__text">
|
|
<strong>{{ 'SETTINGS.LINK_BLOG' | translate }}</strong>
|
|
<span>{{
|
|
'SETTINGS.LINK_BLOG_DESCRIPTION' | translate
|
|
}}</span>
|
|
</span>
|
|
<mat-icon class="link-card__arrow">arrow_outward</mat-icon>
|
|
</a>
|
|
<a
|
|
class="link-card link-card--telegram"
|
|
href="https://t.me/iptvnator"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
data-test-id="link-telegram"
|
|
>
|
|
<span class="link-card__glyph">
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
<path
|
|
fill="currentColor"
|
|
d="M9.78 18.65l.28-4.23 7.68-6.92c.34-.31-.07-.46-.52-.19L7.74 13.3 3.64 12c-.88-.25-.89-.86.2-1.3l15.97-6.16c.73-.33 1.43.18 1.15 1.3l-2.72 12.81c-.19.91-.74 1.13-1.5.71L12.6 16.3l-1.99 1.93c-.23.23-.42.42-.83.42z"
|
|
/>
|
|
</svg>
|
|
</span>
|
|
<span class="link-card__text">
|
|
<strong>Telegram</strong>
|
|
<span>{{
|
|
'SETTINGS.LINK_TELEGRAM_DESCRIPTION' | translate
|
|
}}</span>
|
|
</span>
|
|
<mat-icon class="link-card__arrow">arrow_outward</mat-icon>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="setting-item setting-item--full-control">
|
|
<div class="support-card" data-test-id="support-card">
|
|
<div class="support-card__intro">
|
|
<div class="support-card__emblem">
|
|
<mat-icon>favorite</mat-icon>
|
|
</div>
|
|
<div class="support-card__copy">
|
|
<h4>{{ 'SETTINGS.SUPPORT_TITLE' | translate }}</h4>
|
|
<p>{{ 'SETTINGS.SUPPORT_DESCRIPTION' | translate }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="support-card__actions">
|
|
<a
|
|
class="support-btn support-btn--sponsors"
|
|
href="https://github.com/sponsors/4gray"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
data-test-id="support-sponsors"
|
|
>
|
|
<span class="support-btn__glyph">
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
<path
|
|
fill="currentColor"
|
|
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
|
|
/>
|
|
</svg>
|
|
</span>
|
|
<span class="support-btn__text">
|
|
<strong>GitHub Sponsors</strong>
|
|
<small>{{
|
|
'SETTINGS.SUPPORT_SPONSORS_HINT' | translate
|
|
}}</small>
|
|
</span>
|
|
</a>
|
|
<a
|
|
class="support-btn support-btn--kofi"
|
|
href="https://ko-fi.com/4gray"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
data-test-id="support-kofi"
|
|
>
|
|
<span class="support-btn__glyph">
|
|
<mat-icon>local_cafe</mat-icon>
|
|
</span>
|
|
<span class="support-btn__text">
|
|
<strong>Ko-fi</strong>
|
|
<small>{{
|
|
'SETTINGS.SUPPORT_KOFI_HINT' | translate
|
|
}}</small>
|
|
</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|