mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
chore: tighten validation and runtime logging
* chore: tighten validation and runtime logging * fix(i18n): localize new settings labels
This commit is contained in:
1 parent
d24c77a143
commit
2d5c4fa4f9
52 files changed
+767
-214
No files matched your search
@@ -26,9 +26,7 @@ import { ChannelActions } from '@iptvnator/m3u-state';
|
||||
@if (displayIcon() && !logoError()) {
|
||||
<div
|
||||
class="backdrop"
|
||||
[style.backgroundImage]="
|
||||
'url(' + displayIcon() + ')'
|
||||
"
|
||||
[style.backgroundImage]="'url(' + displayIcon() + ')'"
|
||||
></div>
|
||||
}
|
||||
<div class="vignette"></div>
|
||||
@@ -54,7 +52,10 @@ import { ChannelActions } from '@iptvnator/m3u-state';
|
||||
<h2 class="station-name">
|
||||
{{ channelName() || 'Radio' }}
|
||||
</h2>
|
||||
<span class="station-badge" [class.live]="playState() === 'play'">
|
||||
<span
|
||||
class="station-badge"
|
||||
[class.live]="playState() === 'play'"
|
||||
>
|
||||
@if (playState() === 'play') {
|
||||
<span class="pulse"></span> LIVE
|
||||
} @else {
|
||||
@@ -74,14 +75,10 @@ import { ChannelActions } from '@iptvnator/m3u-state';
|
||||
<button
|
||||
class="play-btn"
|
||||
mat-fab
|
||||
(click)="
|
||||
playState() === 'play' ? stop() : play()
|
||||
"
|
||||
(click)="playState() === 'play' ? stop() : play()"
|
||||
>
|
||||
<mat-icon>{{
|
||||
playState() === 'play'
|
||||
? 'pause'
|
||||
: 'play_arrow'
|
||||
playState() === 'play' ? 'pause' : 'play_arrow'
|
||||
}}</mat-icon>
|
||||
</button>
|
||||
|
||||
@@ -95,19 +92,10 @@ import { ChannelActions } from '@iptvnator/m3u-state';
|
||||
</div>
|
||||
|
||||
<div class="volume-row">
|
||||
<button
|
||||
mat-icon-button
|
||||
class="vol-icon"
|
||||
(click)="mute()"
|
||||
>
|
||||
<button mat-icon-button class="vol-icon" (click)="mute()">
|
||||
<mat-icon>{{ volumeIcon() }}</mat-icon>
|
||||
</button>
|
||||
<mat-slider
|
||||
class="vol-slider"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
>
|
||||
<mat-slider class="vol-slider" min="0" max="1" step="0.05">
|
||||
<input
|
||||
matSliderThumb
|
||||
[ngModel]="volume()"
|
||||
@@ -209,7 +197,9 @@ export class AudioPlayerComponent {
|
||||
play() {
|
||||
const audio = this.audioRef()?.nativeElement;
|
||||
if (!audio) return;
|
||||
audio.play().catch((err) => console.log(err));
|
||||
audio.play().catch((err) => {
|
||||
console.warn('[AudioPlayer] Audio playback failed:', err);
|
||||
});
|
||||
this.playState.set('play');
|
||||
}
|
||||
|
||||
@@ -219,8 +209,7 @@ export class AudioPlayerComponent {
|
||||
}
|
||||
|
||||
setVolume(value: number) {
|
||||
const clamped =
|
||||
Math.round(Math.max(0, Math.min(1, value)) * 100) / 100;
|
||||
const clamped = Math.round(Math.max(0, Math.min(1, value)) * 100) / 100;
|
||||
this.volume.set(clamped);
|
||||
const audio = this.audioRef()?.nativeElement;
|
||||
if (audio) audio.volume = clamped;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import Hls, { type ErrorData, type ManifestParsedData } from 'hls.js';
|
||||
import mpegts from 'mpegts.js';
|
||||
import { DataService } from '@iptvnator/services';
|
||||
import { Channel } from '@iptvnator/shared/interfaces';
|
||||
import { Channel, createDevLogger } from '@iptvnator/shared/interfaces';
|
||||
import {
|
||||
InlinePlaybackPlayer,
|
||||
PlaybackDiagnostic,
|
||||
@@ -26,6 +26,8 @@ import {
|
||||
getPlaybackMediaExtensionFromUrl,
|
||||
} from '../playback-diagnostics/playback-diagnostics.util';
|
||||
|
||||
const debugHtmlPlayer = createDevLogger('HtmlVideoPlayer');
|
||||
|
||||
/**
|
||||
* This component contains the implementation of HTML5 based video player
|
||||
*/
|
||||
@@ -121,7 +123,7 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.playChannel(changes['channel'].currentValue);
|
||||
}
|
||||
if (changes['volume']?.currentValue !== undefined) {
|
||||
console.log(
|
||||
debugHtmlPlayer(
|
||||
'Setting HTML5 player volume to:',
|
||||
changes['volume'].currentValue
|
||||
);
|
||||
@@ -157,7 +159,7 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
if ((extension === 'ts' || !extension) && mpegts.isSupported()) {
|
||||
console.log(
|
||||
debugHtmlPlayer(
|
||||
'Using mpegts.js for TS stream:',
|
||||
channel.name,
|
||||
url
|
||||
@@ -193,7 +195,7 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
Hls &&
|
||||
Hls.isSupported()
|
||||
) {
|
||||
console.log('... switching channel to ', channel.name, url);
|
||||
debugHtmlPlayer('Switching channel to:', channel.name, url);
|
||||
this.hls = new Hls();
|
||||
this.hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {
|
||||
this.handleHlsManifestParsed(url, data);
|
||||
@@ -205,7 +207,7 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.hls.loadSource(url);
|
||||
this.handlePlayOperation();
|
||||
} else {
|
||||
console.log('Using native video player...');
|
||||
debugHtmlPlayer('Using native video player');
|
||||
this.addSourceToVideo(
|
||||
this.videoPlayer.nativeElement,
|
||||
url,
|
||||
@@ -315,7 +317,7 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
*/
|
||||
onVolumeChange(): void {
|
||||
const currentVolume = this.videoPlayer.nativeElement.volume;
|
||||
console.log('Volume changed to:', currentVolume);
|
||||
debugHtmlPlayer('Volume changed to:', currentVolume);
|
||||
localStorage.setItem('volume', currentVolume.toString());
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import '@yangkghjh/videojs-aspect-ratio-panel';
|
||||
import mpegts from 'mpegts.js';
|
||||
import { createDevLogger } from '@iptvnator/shared/interfaces';
|
||||
import videoJs from 'video.js';
|
||||
import 'videojs-contrib-quality-levels';
|
||||
import 'videojs-quality-selector-hls';
|
||||
@@ -89,6 +90,8 @@ type VideoJsPlayer = Omit<
|
||||
error: () => { code?: number; message?: string } | null;
|
||||
};
|
||||
|
||||
const debugVjsPlayer = createDevLogger('VjsPlayer');
|
||||
|
||||
@Component({
|
||||
selector: 'app-vjs-player',
|
||||
templateUrl: './vjs-player.component.html',
|
||||
@@ -145,7 +148,7 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
: { ...this.options(), autoplay: true };
|
||||
|
||||
this.player = videoJs(this.target().nativeElement, vjsOptions, () => {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'Setting VideoJS player initial volume to:',
|
||||
this.volume()
|
||||
);
|
||||
@@ -168,7 +171,7 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
const audioTracks = this.player.audioTracks();
|
||||
if (audioTracks) {
|
||||
audioTracks.addEventListener('addtrack', () => {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] addtrack event fired, total tracks:',
|
||||
this.player.audioTracks().length
|
||||
);
|
||||
@@ -176,7 +179,7 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.setupAudioTrackMenu();
|
||||
});
|
||||
audioTracks.addEventListener('removetrack', () => {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] removetrack event fired, total tracks:',
|
||||
this.player.audioTracks().length
|
||||
);
|
||||
@@ -246,7 +249,7 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
}
|
||||
if (changes['volume']?.currentValue !== undefined && this.player) {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'Setting VideoJS player volume to:',
|
||||
changes['volume'].currentValue
|
||||
);
|
||||
@@ -300,7 +303,7 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
?.el();
|
||||
if (!videoEl) return;
|
||||
|
||||
console.log('Using mpegts.js for TS stream:', url);
|
||||
debugVjsPlayer('Using mpegts.js for TS stream:', url);
|
||||
const isLive = this.options().isLive !== false;
|
||||
this.mpegtsPlayer = mpegts.createPlayer({
|
||||
type: 'mpegts',
|
||||
@@ -455,13 +458,13 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
*/
|
||||
private logAudioTracks(): void {
|
||||
const audioTracks = this.player.audioTracks();
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] Audio tracks count:',
|
||||
audioTracks?.length ?? 0
|
||||
);
|
||||
for (let i = 0; i < (audioTracks?.length ?? 0); i++) {
|
||||
const t = audioTracks[i];
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
`[AudioTrack] Track ${i}: label="${t.label}", language="${t.language}", enabled=${t.enabled}, kind="${t.kind}"`
|
||||
);
|
||||
}
|
||||
@@ -476,12 +479,12 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
tech?.vhs?.playlists?.master?.mediaGroups?.AUDIO;
|
||||
|
||||
if (audioMediaGroups) {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] HLS AUDIO media groups:',
|
||||
JSON.stringify(Object.keys(audioMediaGroups))
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] HLS AUDIO media groups: none found in playlist metadata'
|
||||
);
|
||||
}
|
||||
@@ -494,16 +497,16 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
*/
|
||||
private setupAudioTrackMenu(): void {
|
||||
const audioTracks = this.player.audioTracks();
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] setupAudioTrackMenu called, tracks:',
|
||||
audioTracks?.length ?? 0
|
||||
);
|
||||
if (!audioTracks || audioTracks.length <= 1) {
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] Skipping menu: need >1 tracks, have',
|
||||
audioTracks?.length ?? 0
|
||||
);
|
||||
console.log(
|
||||
debugVjsPlayer(
|
||||
'[AudioTrack] If VLC/MPV show more tracks, the HLS manifest likely does not expose alternate audio via EXT-X-MEDIA'
|
||||
);
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user