mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
213 lines
6.8 KiB
TypeScript
213 lines
6.8 KiB
TypeScript
import { OverlayRef } from '@angular/cdk/overlay';
|
|
import {
|
|
AfterViewInit,
|
|
Component,
|
|
ElementRef,
|
|
Inject,
|
|
NgZone,
|
|
OnInit,
|
|
ViewChild,
|
|
} from '@angular/core';
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
import { addDays, differenceInMinutes, format, parse, subDays } from 'date-fns';
|
|
import {
|
|
EPG_GET_CHANNELS_BY_RANGE,
|
|
EPG_GET_CHANNELS_BY_RANGE_RESPONSE,
|
|
} from '../../../../../shared/ipc-commands';
|
|
import { DataService } from '../../../services/data.service';
|
|
import { EpgChannel } from '../../models/epg-channel.model';
|
|
import { EpgProgram } from '../../models/epg-program.model';
|
|
import { EpgItemDescriptionComponent } from '../epg-list/epg-item-description/epg-item-description.component';
|
|
import { COMPONENT_OVERLAY_REF } from '../video-player/video-player.component';
|
|
|
|
@Component({
|
|
selector: 'app-multi-epg-container',
|
|
templateUrl: './multi-epg-container.component.html',
|
|
styleUrls: ['./multi-epg-container.component.scss'],
|
|
})
|
|
export class MultiEpgContainerComponent implements OnInit, AfterViewInit {
|
|
@ViewChild('epgContainer') epgContainer: ElementRef;
|
|
timeHeader = new Array(24);
|
|
hourWidth = 150;
|
|
barHeight = 50;
|
|
originalEpgData: (EpgChannel & { programs: EpgProgram[] })[] = [];
|
|
channels: (EpgChannel & { programs: EpgProgram[] })[] = [];
|
|
today = format(new Date(), 'yyyyMMdd');
|
|
currentTimeLine = 0;
|
|
visibleChannels;
|
|
channelsLowerRange = 0;
|
|
channelsUpperRange;
|
|
|
|
constructor(
|
|
private dataService: DataService,
|
|
private dialog: MatDialog,
|
|
private ngZone: NgZone,
|
|
@Inject(COMPONENT_OVERLAY_REF) private overlayRef: OverlayRef
|
|
) {
|
|
this.dataService.listenOn(
|
|
EPG_GET_CHANNELS_BY_RANGE_RESPONSE,
|
|
(event, response) =>
|
|
this.ngZone.run(() => {
|
|
if (response) {
|
|
this.originalEpgData = response.payload;
|
|
this.channels = this.enrichProgramData();
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.calculateCurrentTimeBar();
|
|
}
|
|
|
|
ngAfterViewInit(): void {
|
|
const timeNow = new Date();
|
|
const scrollPosition =
|
|
(timeNow.getHours() + timeNow.getMinutes() / 60) * this.hourWidth;
|
|
document
|
|
.getElementById('epg-container')!
|
|
.scrollTo(scrollPosition < 1000 ? 0 : scrollPosition - 150, 0);
|
|
|
|
const borderInPx =
|
|
this.epgContainer.nativeElement.offsetHeight / this.barHeight;
|
|
this.visibleChannels = Math.floor(
|
|
(this.epgContainer.nativeElement.offsetHeight - borderInPx) /
|
|
this.barHeight -
|
|
1
|
|
);
|
|
this.channelsUpperRange = this.visibleChannels;
|
|
this.requestPrograms();
|
|
}
|
|
|
|
nextChannels(): void {
|
|
this.channelsLowerRange = this.channelsUpperRange;
|
|
this.channelsUpperRange =
|
|
this.channelsUpperRange + this.visibleChannels;
|
|
this.channels = [];
|
|
this.requestPrograms();
|
|
}
|
|
|
|
previousChannels(): void {
|
|
this.channelsUpperRange =
|
|
this.channelsUpperRange - this.visibleChannels;
|
|
this.channelsLowerRange =
|
|
this.channelsUpperRange - this.visibleChannels;
|
|
|
|
this.requestPrograms();
|
|
}
|
|
|
|
requestPrograms() {
|
|
this.dataService.sendIpcEvent(EPG_GET_CHANNELS_BY_RANGE, {
|
|
limit: this.channelsUpperRange,
|
|
skip: this.channelsLowerRange,
|
|
});
|
|
}
|
|
|
|
enrichProgramData() {
|
|
return this.originalEpgData.map((channel) => {
|
|
return {
|
|
...channel,
|
|
programs: channel.programs
|
|
.filter((item) => item.start.includes(this.today))
|
|
.map((program) => {
|
|
const startDate = parse(
|
|
program.start,
|
|
'yyyyMMddHHmmss XXXX',
|
|
addDays(new Date(), 1)
|
|
);
|
|
const stopDate = parse(
|
|
program.stop,
|
|
'yyyyMMddHHmmss XXXX',
|
|
addDays(new Date(), 1)
|
|
);
|
|
return {
|
|
...program,
|
|
startDate,
|
|
stopDate,
|
|
startPosition: this.positionToStartInPx(startDate),
|
|
width: this.programDurationInPx(
|
|
startDate,
|
|
stopDate
|
|
),
|
|
};
|
|
}),
|
|
};
|
|
});
|
|
}
|
|
|
|
positionToStartInPx(startDate: Date) {
|
|
return (
|
|
(startDate.getHours() + startDate.getMinutes() / 60) *
|
|
this.hourWidth
|
|
);
|
|
}
|
|
|
|
programDurationInPx(startDate: Date, stopDate: Date) {
|
|
const duration = differenceInMinutes(stopDate, startDate);
|
|
return (duration * this.hourWidth) / 60;
|
|
}
|
|
|
|
recalculate(): void {
|
|
this.channels.forEach((channel) => {
|
|
channel.programs = channel.programs.map((program: any) => {
|
|
return {
|
|
...program,
|
|
startPosition: this.positionToStartInPx(program.startDate),
|
|
width: this.programDurationInPx(
|
|
program.startDate,
|
|
program.stopDate
|
|
),
|
|
};
|
|
});
|
|
});
|
|
}
|
|
|
|
zoomIn(): void {
|
|
this.hourWidth += 50;
|
|
this.recalculate();
|
|
this.calculateCurrentTimeBar();
|
|
}
|
|
|
|
zoomOut(): void {
|
|
if (this.hourWidth <= 50) return;
|
|
this.hourWidth -= 50;
|
|
this.recalculate();
|
|
this.calculateCurrentTimeBar();
|
|
}
|
|
|
|
calculateCurrentTimeBar(): void {
|
|
const timeNow = new Date();
|
|
this.currentTimeLine =
|
|
(timeNow.getHours() + timeNow.getMinutes() / 60) * this.hourWidth;
|
|
}
|
|
|
|
switchDay(direction: 'prev' | 'next'): void {
|
|
this.today =
|
|
direction === 'prev'
|
|
? format(
|
|
subDays(parse(this.today, 'yyyyMMdd', new Date()), 1),
|
|
'yyyyMMdd'
|
|
)
|
|
: format(
|
|
addDays(parse(this.today, 'yyyyMMdd', new Date()), 1),
|
|
'yyyyMMdd'
|
|
);
|
|
this.calculateCurrentTimeBar();
|
|
this.channels = this.enrichProgramData();
|
|
}
|
|
|
|
/**
|
|
* Opens the dialog with details about the selected program
|
|
* @param program selected epg program
|
|
*/
|
|
showDescription(program: EpgProgram): void {
|
|
this.dialog.open(EpgItemDescriptionComponent, {
|
|
data: program,
|
|
});
|
|
}
|
|
|
|
close() {
|
|
this.overlayRef.detach();
|
|
}
|
|
}
|