Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,66 @@ export interface Channel {
UseEIT: boolean;
Visible: boolean;
XMLTVID: string;
}
}

export interface AddDBChannelRequest {
ATSCMajorChan: number;
ATSCMinorChan: number;
CallSign: string;
ChannelID: number;
ChannelNumber: string; // number sent as string
ChannelName: string;
DefaultAuthority: string;
ExtendedVisible: string;
Format: string;
FrequencyID: string; // null in sample data
Icon: string;
MplexID: number;
ServiceID: number;
ServiceType: number;
SourceID: number;
UseEIT: boolean;
Visible: boolean;
XMLTVID: string;
}

export interface FetchChannelsFromSourceRequest {
SourceId: number;
CardId: number;
WaitForFinish: boolean;
}

export interface GetChannelInfoListRequest {
SourceID: number;
ChannelGroupID: number;
StartIndex: number;
Count: number;
OnlyVisible: boolean;
Details: boolean;
OrderByName: boolean;
GroupByCallsign: boolean;
OnlyTunable: boolean;
}

export interface GetVideoMultiplexListRequest {
SourceID: number;
StartIndex: number;
Count: number;
}

export interface UpdateVideoSourceRequest {
SourceID: number;
SourceName: string;
Grabber: string;
UserId: string;
FreqTable: string;
LineupId: string;
Password: string;
UseEIT: boolean;
ConfigPath: string;
NITId: number;
BouquetId: number;
RegionId: number;
ScanFrequency: number;
LCNOffset: number;
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface BoolResponse {
bool: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
export interface DownloadFileRequest {
URL: string;
StorageGroup: string;
}

export interface StorageGroupRequest {
StorageGroup: string;
}

export interface StorageGroupFileNameRequest {
StorageGroup: string;
FileName: string;
}

export interface GetAlbumArtRequest {
Id: number;
Width: number;
Height: number;
}

export interface GetImageFileRequest {
StorageGroup: string;
FileName: string;
Width: number;
Height: number;
}

export interface GetPreviewImageRequest {
RecordedId: number;
ChanId: number;
StartTime: string; // dateTime
Width: number;
Height: number;
SecsIn: number;
Format: string;
}

export interface GetProgramArtworkListRequest {
Inetref: string;
Season: number;
}

export interface GetRecordingRequest {
RecordedId: number;
ChanId: number;
StartTime: string; // dateTime
}

export interface GetRecordingArtworkRequest {
Type: string;
Inetref: string;
Season: number;
Width: number;
Height: number;
}

export interface GetRecordingArtworkListRequest {
RecordedId: number;
ChanId: number;
StartTime: string; // dateTime
}

export interface GetVideoArtworkRequest {
Type: string;
Id: number;
Width: number;
Height: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface Country {
Code: string;
Country: string;
NativeCountry: string;
Image: string;
}

export interface CountryList {
Countries: Country[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ProgramList } from "./program.interface";

export interface GetRecStorageGroupListResponse {
RecStorageGroupList: String[];
}

export interface GetUpcomingListResponse {
ProgramList: ProgramList;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface CallsignLookupResponse {
iconID: number;
search: string; // Always "callsign"
iconName: string;
urls: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { LIVE_ANNOUNCER_DEFAULT_OPTIONS } from "@angular/cdk/a11y";

export interface GetDDLineupListRequest {
Source: string;
UserId: string;
Password: string;
}

export interface Lineup {
LineupId: string;
Name: string;
DisplayName: string;
Type: string;
Postal: string;
Device: string;
}

export interface LineupList {
Lineups: Lineup[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export interface VideoMultiplex {
MplexId: number;
SourceId: number;
TransportId: number;
NetworkId: number;
Frequency: number;
Inversion: string;
SymbolRate: number;
FEC: string;
Polarity: string;
Modulation: string;
Bandwidth: string;
LPCodeRate: string;
HPCodeRate: string;
TransmissionMode: string;
GuardInterval: string;
Visible: boolean;
Constellation: string;
Hierarchy: string;
ModulationSystems: string;
RollOff: string;
SIStandard: string;
ServiceVersion: number;
UpdateTimeStamp: string; // dateTime
DefaultAuthority: string;
}

export interface VideoMultiplexList {
StartIndex: number;
Count: number;
CurrentPage: number;
TotalPages: number;
TotalAvailable: number;
AsOf: string; // dateTime
Version: string;
ProtoVer: string;
VideoMultiplexes: VideoMultiplex[];
}
17 changes: 15 additions & 2 deletions mythtv/html/backend/src/app/services/interfaces/myth.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { StorageGroupDirList } from "./storagegroup.interface";

export interface MythHostName {
String: string; // That's what the service returns as the key
}
Expand Down Expand Up @@ -62,6 +64,17 @@ export interface PutSettingRequest {
Value: string;
}

export interface PutSettingResponse {
bool: boolean;
export interface GetStorageGroupDirsRequest {
GroupName?: string;
HostName?: string;
}

export interface GetStorageGroupDirsResponse {
StorageGroupDirList: StorageGroupDirList;
}

export interface AddStorageGroupDirRequest {
GroupName: string;
DirName: string;
HostName: string;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@

export interface StorageGroup {
Deleted: number; // Boolean?
Directory: string;
Expirable: number; // Boolean?
Free: number;
Id: string;
LiveTV: number;
Total: number;
Used: number;
Deleted: number; // Boolean?
Directory: string;
Expirable: number; // Boolean?
Free: number;
Id: string;
LiveTV: number;
Total: number;
Used: number;
}

export interface StorageGroupDir {
Id: number;
GroupName: string;
HostName: string;
DirName: string;
DirRead: boolean;
DirWrite: boolean;
KiBFree: number;
}

export interface StorageGroupDirList {
StorageGroupDirs: StorageGroupDir[];
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface VideoSource {
Id: number;
SourceName: string;
Grabber: string;
UserId: string;
Expand All @@ -12,4 +13,11 @@ export interface VideoSource {
RegionId: number;
ScanFrequency: number;
LCNOffset: number;
}
}

export interface VideoSourceList {
AsOf: string; // dateTime
Version: string;
ProtoVer: string;
VideoSources: VideoSource[];
}
38 changes: 31 additions & 7 deletions mythtv/html/backend/src/app/services/myth.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams, HttpErrorResponse} from '@angular/common/http';
import { HttpClient, HttpParams} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { MythHostName, MythTimeZone, MythConnectionInfo, Database, GetSettingRequest, GetSettingResponse, PutSettingRequest, PutSettingResponse } from './interfaces/myth.interface';
import {
MythHostName,
MythTimeZone,
MythConnectionInfo,
Database,
GetSettingRequest,
GetSettingResponse,
PutSettingRequest,
GetStorageGroupDirsRequest,
GetStorageGroupDirsResponse,
AddStorageGroupDirRequest,
} from './interfaces/myth.interface';
import { BoolResponse } from './interfaces/common.interface';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -31,13 +42,26 @@ export class MythService {
return this.httpClient.get<GetSettingResponse>('/Myth/GetSetting', {params})
}

public PutSetting(setting: PutSettingRequest) : Observable<PutSettingResponse> {
public PutSetting(setting: PutSettingRequest) : Observable<BoolResponse> {
console.log(setting);
return this.httpClient.post<PutSettingResponse>('/Myth/PutSetting', setting)
return this.httpClient.post<BoolResponse>('/Myth/PutSetting', setting)
}

public SetConnectionInfo(data: Database) : Observable<PutSettingResponse> {
public SetConnectionInfo(data: Database) : Observable<BoolResponse> {
console.log("SetConnectionInfo :-" + data.Name);
return this.httpClient.post<PutSettingResponse>('/Myth/SetConnectionInfo', data)
return this.httpClient.post<BoolResponse>('/Myth/SetConnectionInfo', data)
}

public GetStorageGroupDirs(request? : GetStorageGroupDirsRequest) : Observable<GetStorageGroupDirsResponse> {
if ((typeof request !== 'undefined') &&
((typeof request.GroupName !== 'undefined') || (typeof request.HostName !== 'undefined'))){
return this.httpClient.post<GetStorageGroupDirsResponse>('/Myth/GetStorageGroupDirs', request);
} else {
return this.httpClient.get<GetStorageGroupDirsResponse>('/Myth/GetStorageGroupDirs');
}
}

public AddStorageGroupDir(request: AddStorageGroupDirRequest) : Observable<BoolResponse> {
return this.httpClient.post<BoolResponse>('/Myth/AddStorageGroupDir', request);
}
}
35 changes: 33 additions & 2 deletions mythtv/html/backend/src/app/testbed/testbed.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ <h1>{{ 'testbed.title' | translate }}</h1><hr>
</div>
<div *ngIf="(m_timezone$ | async)?.TimeZoneInfo as timezone; else loading">
<p>It is currently {{timezone.CurrentDateTime}} in timezone {{timezone.TimeZoneID}}, UTC offset
{{timezone.UTCOffset}} hours</p>
{{timezone.UTCOffset / 3600}} hours</p>
</div>
<div *ngIf="(m_connectionInfo$ | async)?.ConnectionInfo as info; else loadingOrError">
<p>MythTV version is {{info.Version.Version}} from branch {{info.Version.Branch}} using protocol
Expand All @@ -18,6 +18,36 @@ <h1>{{ 'testbed.title' | translate }}</h1><hr>
<!-- <p>Database is "{{dbstatus.Connected ? Connected : Not Connected}}"</p> -->
</div>

<div *ngIf="(m_storageGroupList$ | async)?.RecStorageGroupList as StorageGroupDir; else loading">
<ul>
<ng-container *ngFor="let sg of StorageGroupDir">
<li>Storage Group: {{sg}}</li>
</ng-container>
</ul>
</div>

<div *ngIf="(m_storageGroupDirs$ | async)?.StorageGroupDirList as sgArray; else loading">
<ul>
<ng-container *ngFor="let sg of sgArray.StorageGroupDirs">
<li>SG: {{ sg.GroupName }}, Directory: {{ sg.DirName }}</li>
</ng-container>
</ul>
</div>

<div *ngIf="(m_iconUrl$ | async)?.urls as url; else loading">
<img src={{url}} height="57"/>
</div>

<div *ngIf="(m_downloadTest$ | async) as x; else loading">
<p>File Download {{x.bool}}</p>
</div>

<div *ngIf="(m_addStorageGroupDir$ | async) as x; else loading">
<p>Add group {{x.bool}}</p>
</div>

<ng-template #downloadFailed>Failed</ng-template>

<ng-template #loadingOrError>
<div *ngIf="errorRes else loading">
<p>Failed to get connection info: {{errorRes.message}}</p>
Expand All @@ -33,7 +63,8 @@ <h1>{{ 'testbed.title' | translate }}</h1><hr>


<p-button class="p-2" (click)="setSecurityPin('1234')">Set PIN to 1234</p-button>
<p-button (click)="setSecurityPin('0000')">Set PIN to 0000</p-button>
<p-button class="p-2" (click)="setSecurityPin('0000')">Set PIN to 0000</p-button>
<p-button class="p-2" (click)="addStorageGroup()">Add SG</p-button>

<h4>Translation Test</h4>
<div>{{ 'primeng.passwordPrompt' | translate }}</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { HttpClientModule } from '@angular/common/http';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';

import { TestbedComponent } from './testbed.component';

Expand All @@ -8,7 +10,9 @@ describe('TestbedComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TestbedComponent ]
declarations: [ TestbedComponent ],
imports: [ HttpClientModule,
TranslateModule.forRoot() ]
})
.compileComponents();
});
Expand Down
62 changes: 56 additions & 6 deletions mythtv/html/backend/src/app/testbed/testbed.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { Component, OnInit } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { HttpErrorResponse } from '@angular/common/http';

import { MythService } from '../services/myth.service';
import { ConfigService } from '../services/config.service';
import { MythHostName, MythTimeZone, MythConnectionInfo, GetSettingResponse } from '../services/interfaces/myth.interface';
import { MythDatabaseStatus } from '../services/interfaces/config.interface';
import { HttpErrorResponse } from '@angular/common/http';
import { DvrService } from '../services/dvr.service';
import { ContentService } from '../services/content.service';

import { MythHostName, MythTimeZone, MythConnectionInfo, GetSettingResponse, GetStorageGroupDirsResponse } from '../services/interfaces/myth.interface';
import { MythDatabaseStatus } from '../services/interfaces/config.interface';
import { GetRecStorageGroupListResponse } from '../services/interfaces/dvr.interface';
import { BoolResponse } from '../services/interfaces/common.interface';
import { IconlookupService } from '../services/external/iconlookup.service';
import { CallsignLookupResponse } from '../services/interfaces/iconlookup.interface';
@Component({
selector: 'app-testbed',
templateUrl: './testbed.component.html',
Expand All @@ -20,13 +26,22 @@ export class TestbedComponent implements OnInit {
m_connectionInfo$!: Observable<MythConnectionInfo>;
m_setting$!: Observable<GetSettingResponse>;
m_databaseStatus$!: Observable<MythDatabaseStatus>;
m_storageGroupList$!: Observable<GetRecStorageGroupListResponse>;
m_storageGroupDirs$!: Observable<GetStorageGroupDirsResponse>;
m_downloadTest$!: Observable<BoolResponse>;
m_addStorageGroupDir$!: Observable<BoolResponse>;
m_iconUrl$!: Observable<CallsignLookupResponse>;

m_hostName: string = "";
m_securityPin: string = "";

public errorRes!: HttpErrorResponse;

constructor(private mythService: MythService, private configService: ConfigService) { }
constructor(private mythService: MythService,
private configService: ConfigService,
private contentService: ContentService,
private dvrService: DvrService,
private lookupService: IconlookupService) { }

ngOnInit(): void {
this.m_hostname$ = this.mythService.GetHostName().pipe(
Expand All @@ -49,8 +64,21 @@ export class TestbedComponent implements OnInit {
tap(data => console.log(data))
)

this.m_storageGroupList$ = this.dvrService.GetRecStorageGroupList().pipe(
tap(data => { console.log("Storage Group List: " + data.RecStorageGroupList);})
)

//this.m_storageGroupDirs$ = this.mythService.GetStorageGroupDirs({ GroupName: 'Default' }).pipe(
this.m_storageGroupDirs$ = this.mythService.GetStorageGroupDirs().pipe(
tap(data => { console.log("Directories for SG's " + data.StorageGroupDirList.StorageGroupDirs)})
)

this.m_databaseStatus$ = this.configService.GetDatabaseStatus().pipe(
tap(data => console.log("Database Status: " + data)),
tap(data => console.log("Database Status: " + data.DatabaseStatus.Connected)),
)

this.m_iconUrl$ = this.lookupService.lookupByCallsign('BBC One').pipe(
tap(data => { console.log("Found URL for BBC One Icon = " + data.urls)})
)
}

Expand All @@ -63,5 +91,27 @@ export class TestbedComponent implements OnInit {
this.mythService.PutSetting({HostName: this.m_hostName, Key: "SecurityPin", Value: value})
.subscribe(result => { console.log(result); this.getSecurityPin(); });
}
}

getStorageGroupDirs() {
this.m_storageGroupDirs$ = this.mythService.GetStorageGroupDirs().pipe(
tap(data => { console.log("Storage Group List: " + data); })
)
}

downloadFile() {
this.m_downloadTest$ = this.contentService.DownloadFile({
URL: "https://www.mythtv.org/img/mythtv.png",
StorageGroup: "Default"
}).pipe(
tap(data => { console.log("Downloaded file: " + data.bool)})
)
}

addStorageGroup() {
this.m_addStorageGroupDir$ = this.mythService.AddStorageGroupDir({
GroupName: 'ChannelIcons',
DirName: '~/Videos/ChannelIcons',
HostName: this.m_hostName
})
}
}