improved library scan speeds, added library manager component
-libraries tab now opens a library manager -choose library directory, manually soft scan and rescan -batched db queues -mp3 header-based duration extraction
This commit is contained in:
@@ -5,6 +5,7 @@ import '@components/now-playing/now-playing.ts';
|
||||
import '@components/sidebar/app-sidebar.ts';
|
||||
import '@components/queue-panel/queue-panel.ts';
|
||||
import '@components/playlist-view/playlist-view.ts';
|
||||
import '@components/library-manager/library-manager.ts';
|
||||
import '@awesome.me/webawesome/dist/styles/themes/default.css';
|
||||
import '@awesome.me/webawesome/dist/components/icon/icon.js';
|
||||
import { setBasePath } from '@awesome.me/webawesome/dist/webawesome.js';
|
||||
@@ -36,6 +37,9 @@ document.addEventListener('navigate', (e: Event) => {
|
||||
case 'playlists':
|
||||
mainContent.innerHTML = '<playlist-view></playlist-view>';
|
||||
break;
|
||||
case 'libraries':
|
||||
mainContent.innerHTML = '<library-manager></library-manager>';
|
||||
break;
|
||||
default:
|
||||
mainContent.innerHTML = `<div style="padding: 1em; color: #b3b3b3;">
|
||||
<p>Coming soon: ${view}</p>
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
import { LitElement, html, css } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { EventsOn, EventsOff } from '@runtime/runtime';
|
||||
import { Scan, FullRescan } from '@go/library/Library';
|
||||
import {
|
||||
GetLibraryDirectory,
|
||||
SetLibraryDirectory,
|
||||
} from '@go/config/Config';
|
||||
import { DirectoryPicker } from '@go/frontendutil/FrontendUtil';
|
||||
import { Events } from '../../events';
|
||||
|
||||
@customElement('library-manager')
|
||||
export class LibraryManager extends LitElement {
|
||||
@state() private libraryDirectory = '';
|
||||
@state() private selectedDirectory = '';
|
||||
@state() private scanning = false;
|
||||
@state() private statusMessage = '';
|
||||
|
||||
static override styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
padding: 1.5em;
|
||||
color: #e9ecef;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1em 0;
|
||||
font-size: 1.4em;
|
||||
font-weight: 600;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 2em;
|
||||
padding: 1.25em;
|
||||
background: #2b3035;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 0.75em 0;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
color: #dee2e6;
|
||||
}
|
||||
|
||||
.section-description {
|
||||
margin: 0 0 1em 0;
|
||||
font-size: 0.85em;
|
||||
color: #868e96;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.directory-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.directory-path {
|
||||
flex: 1;
|
||||
padding: 0.5em 0.75em;
|
||||
background: #1a1d20;
|
||||
border: 1px solid #495057;
|
||||
border-radius: 4px;
|
||||
color: #adb5bd;
|
||||
font-size: 0.85em;
|
||||
font-family: monospace;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
.directory-path.has-value {
|
||||
color: #e9ecef;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.5em 1.25em;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85em;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #4263eb;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background: #3b5bdb;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #2f9e44;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-success:hover:not(:disabled) {
|
||||
background: #2b8a3e;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: #e8590c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-warning:hover:not(:disabled) {
|
||||
background: #d9480f;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #e03131;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger:hover:not(:disabled) {
|
||||
background: #c92a2a;
|
||||
}
|
||||
|
||||
.scan-actions {
|
||||
display: flex;
|
||||
gap: 0.75em;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
margin-top: 1.5em;
|
||||
padding: 0.75em 1em;
|
||||
background: #1a1d20;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85em;
|
||||
color: #868e96;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
.status-bar.active {
|
||||
color: #ffd43b;
|
||||
}
|
||||
`;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.loadCurrentDirectory();
|
||||
|
||||
EventsOn(
|
||||
Events.LibraryScanStarted,
|
||||
this.handleScanStarted,
|
||||
);
|
||||
EventsOn(
|
||||
Events.LibraryScanComplete,
|
||||
this.handleScanComplete,
|
||||
);
|
||||
}
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
EventsOff(Events.LibraryScanStarted);
|
||||
EventsOff(Events.LibraryScanComplete);
|
||||
}
|
||||
|
||||
private async loadCurrentDirectory(): Promise<void> {
|
||||
try {
|
||||
const dir = await GetLibraryDirectory();
|
||||
this.libraryDirectory = dir;
|
||||
this.selectedDirectory = dir;
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'Failed to load library directory:',
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private handleScanStarted = (): void => {
|
||||
this.scanning = true;
|
||||
this.statusMessage = 'Scanning...';
|
||||
};
|
||||
|
||||
private handleScanComplete = (): void => {
|
||||
this.scanning = false;
|
||||
this.statusMessage = 'Scan complete.';
|
||||
};
|
||||
|
||||
private handleSelectDirectory = async (): Promise<void> => {
|
||||
try {
|
||||
const dir = await DirectoryPicker();
|
||||
|
||||
if (dir) {
|
||||
this.selectedDirectory = dir;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Directory picker failed:', err);
|
||||
}
|
||||
};
|
||||
|
||||
private handleSaveDirectory = async (): Promise<void> => {
|
||||
if (!this.selectedDirectory) return;
|
||||
|
||||
try {
|
||||
await SetLibraryDirectory(this.selectedDirectory);
|
||||
this.libraryDirectory = this.selectedDirectory;
|
||||
this.statusMessage =
|
||||
'Library directory saved. A scan will start automatically if the directory changed.';
|
||||
} catch (err) {
|
||||
this.statusMessage = `Failed to save directory: ${err}`;
|
||||
console.error('Failed to save directory:', err);
|
||||
}
|
||||
};
|
||||
|
||||
private handleSoftScan = async (): Promise<void> => {
|
||||
try {
|
||||
await Scan();
|
||||
} catch (err) {
|
||||
this.statusMessage = `Scan failed: ${err}`;
|
||||
console.error('Soft scan failed:', err);
|
||||
}
|
||||
};
|
||||
|
||||
private handleFullRescan = async (): Promise<void> => {
|
||||
const confirmed = confirm(
|
||||
'This will delete ALL library data including cover art and re-scan from scratch. Continue?',
|
||||
);
|
||||
|
||||
if (!confirmed) return;
|
||||
|
||||
try {
|
||||
await FullRescan();
|
||||
} catch (err) {
|
||||
this.statusMessage = `Full rescan failed: ${err}`;
|
||||
console.error('Full rescan failed:', err);
|
||||
}
|
||||
};
|
||||
|
||||
private get directoryChanged(): boolean {
|
||||
return (
|
||||
this.selectedDirectory !== this.libraryDirectory
|
||||
);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<h2>Library Manager</h2>
|
||||
|
||||
<div class="section">
|
||||
<p class="section-title">
|
||||
Library Directory
|
||||
</p>
|
||||
<p class="section-description">
|
||||
Select the root directory containing your
|
||||
music files. Changing this will
|
||||
automatically trigger a scan.
|
||||
</p>
|
||||
<div class="directory-row">
|
||||
<div
|
||||
class="directory-path ${this.selectedDirectory ? 'has-value' : ''}"
|
||||
>
|
||||
${this.selectedDirectory ||
|
||||
'No directory selected'}
|
||||
</div>
|
||||
<button
|
||||
class="btn-primary"
|
||||
@click=${this.handleSelectDirectory}
|
||||
>
|
||||
Browse
|
||||
</button>
|
||||
<button
|
||||
class="btn-success"
|
||||
?disabled=${!this.directoryChanged ||
|
||||
this.scanning}
|
||||
@click=${this.handleSaveDirectory}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<p class="section-title">Scan Actions</p>
|
||||
<p class="section-description">
|
||||
Soft scan finds new files, skips existing
|
||||
ones, and removes orphaned entries. Full
|
||||
rescan clears the entire database and
|
||||
cover art cache, then re-imports
|
||||
everything.
|
||||
</p>
|
||||
<div class="scan-actions">
|
||||
<button
|
||||
class="btn-warning"
|
||||
?disabled=${this.scanning}
|
||||
@click=${this.handleSoftScan}
|
||||
>
|
||||
${this.scanning
|
||||
? 'Scanning...'
|
||||
: 'Soft Scan'}
|
||||
</button>
|
||||
<button
|
||||
class="btn-danger"
|
||||
?disabled=${this.scanning}
|
||||
@click=${this.handleFullRescan}
|
||||
>
|
||||
${this.scanning
|
||||
? 'Scanning...'
|
||||
: 'Full Rescan'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="status-bar ${this.scanning ? 'active' : ''}"
|
||||
>
|
||||
${this.statusMessage || 'Ready.'}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ export const Events = {
|
||||
RequestRemoveTracksFromQueue: "RequestRemoveTracksFromQueue",
|
||||
|
||||
// Library events
|
||||
LibraryScanStarted: "LibraryScanStarted",
|
||||
LibraryScanComplete: "LibraryScanComplete",
|
||||
} as const;
|
||||
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
import {http} from '../models';
|
||||
import {context} from '../models';
|
||||
|
||||
export function GetLibraryDirectory():Promise<string>;
|
||||
|
||||
export function Load():Promise<void>;
|
||||
|
||||
export function Save():Promise<void>;
|
||||
|
||||
export function ServeHTTP(arg1:http.ResponseWriter,arg2:http.Request):Promise<void>;
|
||||
|
||||
export function SetContext(arg1:context.Context):Promise<void>;
|
||||
|
||||
export function SetLibraryDirectory(arg1:string):Promise<void>;
|
||||
|
||||
export function Validate():Promise<void>;
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function GetLibraryDirectory() {
|
||||
return window['go']['config']['Config']['GetLibraryDirectory']();
|
||||
}
|
||||
|
||||
export function Load() {
|
||||
return window['go']['config']['Config']['Load']();
|
||||
}
|
||||
|
||||
export function Save() {
|
||||
return window['go']['config']['Config']['Save']();
|
||||
}
|
||||
|
||||
export function ServeHTTP(arg1, arg2) {
|
||||
return window['go']['config']['Config']['ServeHTTP'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function SetContext(arg1) {
|
||||
return window['go']['config']['Config']['SetContext'](arg1);
|
||||
}
|
||||
|
||||
export function SetLibraryDirectory(arg1) {
|
||||
return window['go']['config']['Config']['SetLibraryDirectory'](arg1);
|
||||
}
|
||||
|
||||
export function Validate() {
|
||||
return window['go']['config']['Config']['Validate']();
|
||||
}
|
||||
+4
@@ -3,6 +3,8 @@
|
||||
import {library} from '../models';
|
||||
import {context} from '../models';
|
||||
|
||||
export function FullRescan():Promise<void>;
|
||||
|
||||
export function GetAlbumTracks(arg1:number):Promise<Array<library.Track>>;
|
||||
|
||||
export function GetAllAlbums():Promise<Array<library.Album>>;
|
||||
@@ -12,3 +14,5 @@ export function GetAllTracks():Promise<Array<library.Track>>;
|
||||
export function Scan():Promise<void>;
|
||||
|
||||
export function SetContext(arg1:context.Context):Promise<void>;
|
||||
|
||||
export function SetQueue(arg1:library.queueClearer):Promise<void>;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function FullRescan() {
|
||||
return window['go']['library']['Library']['FullRescan']();
|
||||
}
|
||||
|
||||
export function GetAlbumTracks(arg1) {
|
||||
return window['go']['library']['Library']['GetAlbumTracks'](arg1);
|
||||
}
|
||||
@@ -21,3 +25,7 @@ export function Scan() {
|
||||
export function SetContext(arg1) {
|
||||
return window['go']['library']['Library']['SetContext'](arg1);
|
||||
}
|
||||
|
||||
export function SetQueue(arg1) {
|
||||
return window['go']['library']['Library']['SetQueue'](arg1);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,132 @@
|
||||
export namespace http {
|
||||
|
||||
export class Response {
|
||||
Status: string;
|
||||
StatusCode: number;
|
||||
Proto: string;
|
||||
ProtoMajor: number;
|
||||
ProtoMinor: number;
|
||||
Header: Record<string, Array<string>>;
|
||||
Body: any;
|
||||
ContentLength: number;
|
||||
TransferEncoding: string[];
|
||||
Close: boolean;
|
||||
Uncompressed: boolean;
|
||||
Trailer: Record<string, Array<string>>;
|
||||
Request?: Request;
|
||||
TLS?: tls.ConnectionState;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Response(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Status = source["Status"];
|
||||
this.StatusCode = source["StatusCode"];
|
||||
this.Proto = source["Proto"];
|
||||
this.ProtoMajor = source["ProtoMajor"];
|
||||
this.ProtoMinor = source["ProtoMinor"];
|
||||
this.Header = source["Header"];
|
||||
this.Body = source["Body"];
|
||||
this.ContentLength = source["ContentLength"];
|
||||
this.TransferEncoding = source["TransferEncoding"];
|
||||
this.Close = source["Close"];
|
||||
this.Uncompressed = source["Uncompressed"];
|
||||
this.Trailer = source["Trailer"];
|
||||
this.Request = this.convertValues(source["Request"], Request);
|
||||
this.TLS = this.convertValues(source["TLS"], tls.ConnectionState);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
export class Request {
|
||||
Method: string;
|
||||
URL?: url.URL;
|
||||
Proto: string;
|
||||
ProtoMajor: number;
|
||||
ProtoMinor: number;
|
||||
Header: Record<string, Array<string>>;
|
||||
Body: any;
|
||||
ContentLength: number;
|
||||
TransferEncoding: string[];
|
||||
Close: boolean;
|
||||
Host: string;
|
||||
Form: Record<string, Array<string>>;
|
||||
PostForm: Record<string, Array<string>>;
|
||||
MultipartForm?: multipart.Form;
|
||||
Trailer: Record<string, Array<string>>;
|
||||
RemoteAddr: string;
|
||||
RequestURI: string;
|
||||
TLS?: tls.ConnectionState;
|
||||
Response?: Response;
|
||||
Pattern: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Request(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Method = source["Method"];
|
||||
this.URL = this.convertValues(source["URL"], url.URL);
|
||||
this.Proto = source["Proto"];
|
||||
this.ProtoMajor = source["ProtoMajor"];
|
||||
this.ProtoMinor = source["ProtoMinor"];
|
||||
this.Header = source["Header"];
|
||||
this.Body = source["Body"];
|
||||
this.ContentLength = source["ContentLength"];
|
||||
this.TransferEncoding = source["TransferEncoding"];
|
||||
this.Close = source["Close"];
|
||||
this.Host = source["Host"];
|
||||
this.Form = source["Form"];
|
||||
this.PostForm = source["PostForm"];
|
||||
this.MultipartForm = this.convertValues(source["MultipartForm"], multipart.Form);
|
||||
this.Trailer = source["Trailer"];
|
||||
this.RemoteAddr = source["RemoteAddr"];
|
||||
this.RequestURI = source["RequestURI"];
|
||||
this.TLS = this.convertValues(source["TLS"], tls.ConnectionState);
|
||||
this.Response = this.convertValues(source["Response"], Response);
|
||||
this.Pattern = source["Pattern"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace library {
|
||||
|
||||
export class Album {
|
||||
@@ -51,6 +180,163 @@ export namespace library {
|
||||
|
||||
}
|
||||
|
||||
export namespace multipart {
|
||||
|
||||
export class FileHeader {
|
||||
Filename: string;
|
||||
Header: Record<string, Array<string>>;
|
||||
Size: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new FileHeader(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Filename = source["Filename"];
|
||||
this.Header = source["Header"];
|
||||
this.Size = source["Size"];
|
||||
}
|
||||
}
|
||||
export class Form {
|
||||
Value: Record<string, Array<string>>;
|
||||
File: Record<string, Array<FileHeader>>;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Form(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Value = source["Value"];
|
||||
this.File = this.convertValues(source["File"], Array<FileHeader>, true);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace net {
|
||||
|
||||
export class IPNet {
|
||||
IP: number[];
|
||||
Mask: number[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new IPNet(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.IP = source["IP"];
|
||||
this.Mask = source["Mask"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace pkix {
|
||||
|
||||
export class AttributeTypeAndValue {
|
||||
Type: number[];
|
||||
Value: any;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AttributeTypeAndValue(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Type = source["Type"];
|
||||
this.Value = source["Value"];
|
||||
}
|
||||
}
|
||||
export class Extension {
|
||||
Id: number[];
|
||||
Critical: boolean;
|
||||
Value: number[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Extension(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Id = source["Id"];
|
||||
this.Critical = source["Critical"];
|
||||
this.Value = source["Value"];
|
||||
}
|
||||
}
|
||||
export class Name {
|
||||
Country: string[];
|
||||
Organization: string[];
|
||||
OrganizationalUnit: string[];
|
||||
Locality: string[];
|
||||
Province: string[];
|
||||
StreetAddress: string[];
|
||||
PostalCode: string[];
|
||||
SerialNumber: string;
|
||||
CommonName: string;
|
||||
Names: AttributeTypeAndValue[];
|
||||
ExtraNames: AttributeTypeAndValue[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Name(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Country = source["Country"];
|
||||
this.Organization = source["Organization"];
|
||||
this.OrganizationalUnit = source["OrganizationalUnit"];
|
||||
this.Locality = source["Locality"];
|
||||
this.Province = source["Province"];
|
||||
this.StreetAddress = source["StreetAddress"];
|
||||
this.PostalCode = source["PostalCode"];
|
||||
this.SerialNumber = source["SerialNumber"];
|
||||
this.CommonName = source["CommonName"];
|
||||
this.Names = this.convertValues(source["Names"], AttributeTypeAndValue);
|
||||
this.ExtraNames = this.convertValues(source["ExtraNames"], AttributeTypeAndValue);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace playlist {
|
||||
|
||||
export class Summary {
|
||||
@@ -134,3 +420,318 @@ export namespace playlist {
|
||||
|
||||
}
|
||||
|
||||
export namespace tls {
|
||||
|
||||
export class ConnectionState {
|
||||
Version: number;
|
||||
HandshakeComplete: boolean;
|
||||
DidResume: boolean;
|
||||
CipherSuite: number;
|
||||
CurveID: number;
|
||||
NegotiatedProtocol: string;
|
||||
NegotiatedProtocolIsMutual: boolean;
|
||||
ServerName: string;
|
||||
PeerCertificates: x509.Certificate[];
|
||||
VerifiedChains: x509.Certificate[][];
|
||||
SignedCertificateTimestamps: number[][];
|
||||
OCSPResponse: number[];
|
||||
TLSUnique: number[];
|
||||
ECHAccepted: boolean;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new ConnectionState(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Version = source["Version"];
|
||||
this.HandshakeComplete = source["HandshakeComplete"];
|
||||
this.DidResume = source["DidResume"];
|
||||
this.CipherSuite = source["CipherSuite"];
|
||||
this.CurveID = source["CurveID"];
|
||||
this.NegotiatedProtocol = source["NegotiatedProtocol"];
|
||||
this.NegotiatedProtocolIsMutual = source["NegotiatedProtocolIsMutual"];
|
||||
this.ServerName = source["ServerName"];
|
||||
this.PeerCertificates = this.convertValues(source["PeerCertificates"], x509.Certificate);
|
||||
this.VerifiedChains = this.convertValues(source["VerifiedChains"], x509.Certificate);
|
||||
this.SignedCertificateTimestamps = source["SignedCertificateTimestamps"];
|
||||
this.OCSPResponse = source["OCSPResponse"];
|
||||
this.TLSUnique = source["TLSUnique"];
|
||||
this.ECHAccepted = source["ECHAccepted"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace url {
|
||||
|
||||
export class Userinfo {
|
||||
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Userinfo(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
|
||||
}
|
||||
}
|
||||
export class URL {
|
||||
Scheme: string;
|
||||
Opaque: string;
|
||||
// Go type: Userinfo
|
||||
User?: any;
|
||||
Host: string;
|
||||
Path: string;
|
||||
RawPath: string;
|
||||
OmitHost: boolean;
|
||||
ForceQuery: boolean;
|
||||
RawQuery: string;
|
||||
Fragment: string;
|
||||
RawFragment: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new URL(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Scheme = source["Scheme"];
|
||||
this.Opaque = source["Opaque"];
|
||||
this.User = this.convertValues(source["User"], null);
|
||||
this.Host = source["Host"];
|
||||
this.Path = source["Path"];
|
||||
this.RawPath = source["RawPath"];
|
||||
this.OmitHost = source["OmitHost"];
|
||||
this.ForceQuery = source["ForceQuery"];
|
||||
this.RawQuery = source["RawQuery"];
|
||||
this.Fragment = source["Fragment"];
|
||||
this.RawFragment = source["RawFragment"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace x509 {
|
||||
|
||||
export class PolicyMapping {
|
||||
// Go type: OID
|
||||
IssuerDomainPolicy: any;
|
||||
// Go type: OID
|
||||
SubjectDomainPolicy: any;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new PolicyMapping(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.IssuerDomainPolicy = this.convertValues(source["IssuerDomainPolicy"], null);
|
||||
this.SubjectDomainPolicy = this.convertValues(source["SubjectDomainPolicy"], null);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
export class OID {
|
||||
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new OID(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
|
||||
}
|
||||
}
|
||||
export class Certificate {
|
||||
Raw: number[];
|
||||
RawTBSCertificate: number[];
|
||||
RawSubjectPublicKeyInfo: number[];
|
||||
RawSubject: number[];
|
||||
RawIssuer: number[];
|
||||
Signature: number[];
|
||||
SignatureAlgorithm: number;
|
||||
PublicKeyAlgorithm: number;
|
||||
PublicKey: any;
|
||||
Version: number;
|
||||
// Go type: big
|
||||
SerialNumber?: any;
|
||||
Issuer: pkix.Name;
|
||||
Subject: pkix.Name;
|
||||
// Go type: time
|
||||
NotBefore: any;
|
||||
// Go type: time
|
||||
NotAfter: any;
|
||||
KeyUsage: number;
|
||||
Extensions: pkix.Extension[];
|
||||
ExtraExtensions: pkix.Extension[];
|
||||
UnhandledCriticalExtensions: number[][];
|
||||
ExtKeyUsage: number[];
|
||||
UnknownExtKeyUsage: number[][];
|
||||
BasicConstraintsValid: boolean;
|
||||
IsCA: boolean;
|
||||
MaxPathLen: number;
|
||||
MaxPathLenZero: boolean;
|
||||
SubjectKeyId: number[];
|
||||
AuthorityKeyId: number[];
|
||||
OCSPServer: string[];
|
||||
IssuingCertificateURL: string[];
|
||||
DNSNames: string[];
|
||||
EmailAddresses: string[];
|
||||
IPAddresses: number[][];
|
||||
URIs: url.URL[];
|
||||
PermittedDNSDomainsCritical: boolean;
|
||||
PermittedDNSDomains: string[];
|
||||
ExcludedDNSDomains: string[];
|
||||
PermittedIPRanges: net.IPNet[];
|
||||
ExcludedIPRanges: net.IPNet[];
|
||||
PermittedEmailAddresses: string[];
|
||||
ExcludedEmailAddresses: string[];
|
||||
PermittedURIDomains: string[];
|
||||
ExcludedURIDomains: string[];
|
||||
CRLDistributionPoints: string[];
|
||||
PolicyIdentifiers: number[][];
|
||||
Policies: OID[];
|
||||
InhibitAnyPolicy: number;
|
||||
InhibitAnyPolicyZero: boolean;
|
||||
InhibitPolicyMapping: number;
|
||||
InhibitPolicyMappingZero: boolean;
|
||||
RequireExplicitPolicy: number;
|
||||
RequireExplicitPolicyZero: boolean;
|
||||
PolicyMappings: PolicyMapping[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new Certificate(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.Raw = source["Raw"];
|
||||
this.RawTBSCertificate = source["RawTBSCertificate"];
|
||||
this.RawSubjectPublicKeyInfo = source["RawSubjectPublicKeyInfo"];
|
||||
this.RawSubject = source["RawSubject"];
|
||||
this.RawIssuer = source["RawIssuer"];
|
||||
this.Signature = source["Signature"];
|
||||
this.SignatureAlgorithm = source["SignatureAlgorithm"];
|
||||
this.PublicKeyAlgorithm = source["PublicKeyAlgorithm"];
|
||||
this.PublicKey = source["PublicKey"];
|
||||
this.Version = source["Version"];
|
||||
this.SerialNumber = this.convertValues(source["SerialNumber"], null);
|
||||
this.Issuer = this.convertValues(source["Issuer"], pkix.Name);
|
||||
this.Subject = this.convertValues(source["Subject"], pkix.Name);
|
||||
this.NotBefore = this.convertValues(source["NotBefore"], null);
|
||||
this.NotAfter = this.convertValues(source["NotAfter"], null);
|
||||
this.KeyUsage = source["KeyUsage"];
|
||||
this.Extensions = this.convertValues(source["Extensions"], pkix.Extension);
|
||||
this.ExtraExtensions = this.convertValues(source["ExtraExtensions"], pkix.Extension);
|
||||
this.UnhandledCriticalExtensions = source["UnhandledCriticalExtensions"];
|
||||
this.ExtKeyUsage = source["ExtKeyUsage"];
|
||||
this.UnknownExtKeyUsage = source["UnknownExtKeyUsage"];
|
||||
this.BasicConstraintsValid = source["BasicConstraintsValid"];
|
||||
this.IsCA = source["IsCA"];
|
||||
this.MaxPathLen = source["MaxPathLen"];
|
||||
this.MaxPathLenZero = source["MaxPathLenZero"];
|
||||
this.SubjectKeyId = source["SubjectKeyId"];
|
||||
this.AuthorityKeyId = source["AuthorityKeyId"];
|
||||
this.OCSPServer = source["OCSPServer"];
|
||||
this.IssuingCertificateURL = source["IssuingCertificateURL"];
|
||||
this.DNSNames = source["DNSNames"];
|
||||
this.EmailAddresses = source["EmailAddresses"];
|
||||
this.IPAddresses = source["IPAddresses"];
|
||||
this.URIs = this.convertValues(source["URIs"], url.URL);
|
||||
this.PermittedDNSDomainsCritical = source["PermittedDNSDomainsCritical"];
|
||||
this.PermittedDNSDomains = source["PermittedDNSDomains"];
|
||||
this.ExcludedDNSDomains = source["ExcludedDNSDomains"];
|
||||
this.PermittedIPRanges = this.convertValues(source["PermittedIPRanges"], net.IPNet);
|
||||
this.ExcludedIPRanges = this.convertValues(source["ExcludedIPRanges"], net.IPNet);
|
||||
this.PermittedEmailAddresses = source["PermittedEmailAddresses"];
|
||||
this.ExcludedEmailAddresses = source["ExcludedEmailAddresses"];
|
||||
this.PermittedURIDomains = source["PermittedURIDomains"];
|
||||
this.ExcludedURIDomains = source["ExcludedURIDomains"];
|
||||
this.CRLDistributionPoints = source["CRLDistributionPoints"];
|
||||
this.PolicyIdentifiers = source["PolicyIdentifiers"];
|
||||
this.Policies = this.convertValues(source["Policies"], OID);
|
||||
this.InhibitAnyPolicy = source["InhibitAnyPolicy"];
|
||||
this.InhibitAnyPolicyZero = source["InhibitAnyPolicyZero"];
|
||||
this.InhibitPolicyMapping = source["InhibitPolicyMapping"];
|
||||
this.InhibitPolicyMappingZero = source["InhibitPolicyMappingZero"];
|
||||
this.RequireExplicitPolicy = source["RequireExplicitPolicy"];
|
||||
this.RequireExplicitPolicyZero = source["RequireExplicitPolicyZero"];
|
||||
this.PolicyMappings = this.convertValues(source["PolicyMappings"], PolicyMapping);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user