mirror of
https://github.com/WowUp/WowUp.git
synced 2026-04-22 15:00:38 -04:00
Lots more wago support
This commit is contained in:
@@ -157,6 +157,12 @@ export function setPendingOpenUrl(...openUrls: string[]): void {
|
||||
export function initializeIpcHandlers(window: BrowserWindow): void {
|
||||
log.info("process.versions", process.versions);
|
||||
|
||||
// Just forward the token event out to the window
|
||||
// this is not a handler, just a passive listener
|
||||
ipcMain.on("wago-token-received", (evt, token) => {
|
||||
window?.webContents?.send("wago-token-received", token);
|
||||
});
|
||||
|
||||
// Remove the pending URLs once read so they are only able to be gotten once
|
||||
handle(IPC_GET_PENDING_OPEN_URLS, (): string[] => {
|
||||
const urls = PENDING_OPEN_URLS;
|
||||
@@ -219,7 +225,7 @@ export function initializeIpcHandlers(window: BrowserWindow): void {
|
||||
if (!Array.isArray(addons)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (const addon of addons) {
|
||||
addonStore.set(addon.id, addon);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { WowInstallation } from "../../common/warcraft/wow-installation";
|
||||
import { Observable, of } from "rxjs";
|
||||
|
||||
import { Addon } from "../../common/entities/addon";
|
||||
import { AddonCategory, AddonChannelType } from "../../common/wowup/models";
|
||||
import { AddonCategory, AddonChannelType, AdPageOptions } from "../../common/wowup/models";
|
||||
import { AddonFolder } from "../models/wowup/addon-folder";
|
||||
import { AddonSearchResult } from "../models/wowup/addon-search-result";
|
||||
import { ProtocolSearchResult } from "../models/wowup/protocol-search-result";
|
||||
@@ -44,6 +44,8 @@ export abstract class AddonProvider {
|
||||
public allowViewAtSource = true;
|
||||
public canShowChangelog = true;
|
||||
public canBatchFetch = false;
|
||||
public authRequired = false;
|
||||
public adRequired = false;
|
||||
|
||||
public getAllBatch(installations: WowInstallation[], addonIds: string[]): Promise<GetAllBatchResult> {
|
||||
return Promise.resolve({
|
||||
@@ -119,4 +121,8 @@ export abstract class AddonProvider {
|
||||
public async getDescription(installation: WowInstallation, externalId: string, addon?: Addon): Promise<string> {
|
||||
return Promise.resolve("");
|
||||
}
|
||||
|
||||
public getAdPageParams(): AdPageOptions | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,18 @@ import { CachingService } from "../services/caching/caching-service";
|
||||
import { CircuitBreakerWrapper, NetworkService } from "../services/network/network.service";
|
||||
import { AddonProvider } from "./addon-provider";
|
||||
import { WowInstallation } from "../../common/warcraft/wow-installation";
|
||||
import { AddonChannelType } from "../../common/wowup/models";
|
||||
import { AddonChannelType, AdPageOptions } from "../../common/wowup/models";
|
||||
import { AddonFolder } from "../models/wowup/addon-folder";
|
||||
import { WowClientGroup, WowClientType } from "../../common/warcraft/wow-client-type";
|
||||
import { AppWowUpScanResult } from "../models/wowup/app-wowup-scan-result";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
import { AddonSearchResult } from "../models/wowup/addon-search-result";
|
||||
import { AddonSearchResultFile } from "../models/wowup/addon-search-result-file";
|
||||
import { Addon } from "../../common/entities/addon";
|
||||
import { convertBbcode } from "../utils/bbcode.utils";
|
||||
|
||||
declare type WagoGameVersion = "retail" | "classic" | "bcc";
|
||||
declare type WagoStability = "stable" | "beta" | "alpha";
|
||||
|
||||
interface WagoFingerprintAddon {
|
||||
hash: string; // hash fingerprint of the folder
|
||||
@@ -26,12 +31,76 @@ interface WagoFingerprintRequest {
|
||||
addons: { [folder: string]: WagoFingerprintAddon };
|
||||
}
|
||||
|
||||
interface WagoSearchResponse {
|
||||
data: WagoSearchResponseItem[];
|
||||
}
|
||||
|
||||
interface WagoSearchResponseItem {
|
||||
display_name: string;
|
||||
id: string;
|
||||
releases: {
|
||||
alpha?: WagoSearchResponseRelease;
|
||||
beta?: WagoSearchResponseRelease;
|
||||
stable?: WagoSearchResponseRelease;
|
||||
};
|
||||
summary: string;
|
||||
thumbnail_image: string;
|
||||
}
|
||||
|
||||
interface WagoSearchResponseRelease {
|
||||
download_link: string;
|
||||
label: string;
|
||||
created_at: string;
|
||||
logical_timestamp: number; // download link expiration time
|
||||
}
|
||||
|
||||
interface WagoAddon {
|
||||
id: string;
|
||||
slug: string;
|
||||
display_name: string;
|
||||
thumbnail_image: string;
|
||||
summary: string;
|
||||
description: string;
|
||||
website: string;
|
||||
gallery: string[];
|
||||
recent_releases: {
|
||||
stable?: WagoRelease;
|
||||
beta?: WagoRelease;
|
||||
alpha?: WagoRelease;
|
||||
};
|
||||
}
|
||||
|
||||
interface WagoRelease {
|
||||
label: string;
|
||||
supported_retail_patch: string;
|
||||
supported_classic_patch: string;
|
||||
supported_bc_patch: string;
|
||||
changelog: string;
|
||||
stability: WagoStability;
|
||||
download_link: string;
|
||||
}
|
||||
|
||||
const WAGO_BASE_URL = "https://addons.wago.io/api/external";
|
||||
const WAGO_AD_URL = "https://addons.wago.io/wowup_ad";
|
||||
const WAGO_AD_REFERRER = "https://wago.io";
|
||||
const WAGO_AD_USER_AGENT =
|
||||
"`Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`"; // the ad requires a normal looking user agent
|
||||
const WAGO_AD_PRELOAD = "preload/wago.js";
|
||||
const WAGO_SEARCH_CACHE_TIME_SEC = 20;
|
||||
const WAGO_DETAILS_CACHE_TIME_SEC = 20;
|
||||
|
||||
export class WagoAddonProvider extends AddonProvider {
|
||||
private readonly _circuitBreaker: CircuitBreakerWrapper;
|
||||
|
||||
private _apiToken = "";
|
||||
private _enabled = true;
|
||||
|
||||
public readonly name = ADDON_PROVIDER_WAGO;
|
||||
public readonly forceIgnore = false;
|
||||
public enabled = true;
|
||||
public authRequired = true;
|
||||
public adRequired = true;
|
||||
public allowEdit = true;
|
||||
|
||||
public constructor(
|
||||
private _electronService: ElectronService,
|
||||
@@ -47,6 +116,8 @@ export class WagoAddonProvider extends AddonProvider {
|
||||
AppConfig.defaultHttpResetTimeoutMs,
|
||||
AppConfig.wagoHttpTimeoutMs
|
||||
);
|
||||
|
||||
this._electronService.on("wago-token-received", this.onWagoTokenReceived);
|
||||
}
|
||||
|
||||
public async scan(
|
||||
@@ -84,6 +155,121 @@ export class WagoAddonProvider extends AddonProvider {
|
||||
console.debug(JSON.stringify(request, null, 2));
|
||||
}
|
||||
|
||||
public async searchByQuery(
|
||||
query: string,
|
||||
installation: WowInstallation,
|
||||
channelType?: AddonChannelType
|
||||
): Promise<AddonSearchResult[]> {
|
||||
if (!this._apiToken) {
|
||||
console.warn("[wago] searchByQuery no api token found");
|
||||
return [];
|
||||
}
|
||||
|
||||
const url = new URL(`${WAGO_BASE_URL}/addons/_search`);
|
||||
url.searchParams.set("query", query);
|
||||
url.searchParams.set("game_version", this.getGameVersion(installation.clientType));
|
||||
url.searchParams.set("stability", this.getStability(channelType));
|
||||
|
||||
const response = await this._cachingService.transaction(
|
||||
url.toString(),
|
||||
() => this._circuitBreaker.getJson<WagoSearchResponse>(url, this.getRequestHeaders()),
|
||||
WAGO_SEARCH_CACHE_TIME_SEC
|
||||
);
|
||||
|
||||
const searchResults = response.data?.map((item) => this.toSearchResult(item)) ?? [];
|
||||
|
||||
console.debug(`[wago] searchByQuery`, response, searchResults);
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
public async getDescription(installation: WowInstallation, externalId: string, addon?: Addon): Promise<string> {
|
||||
try {
|
||||
const response = await this.getAddonById(externalId);
|
||||
return convertBbcode(response?.description ?? "");
|
||||
} catch (e) {
|
||||
console.error(`[wago] failed to get description`, e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public getAdPageParams(): AdPageOptions {
|
||||
return {
|
||||
pageUrl: WAGO_AD_URL,
|
||||
referrer: WAGO_AD_REFERRER,
|
||||
userAgent: WAGO_AD_USER_AGENT,
|
||||
preloadFilePath: WAGO_AD_PRELOAD,
|
||||
};
|
||||
}
|
||||
|
||||
private async getAddonById(addonId: string) {
|
||||
//https://addons.wago.io/api/external/addons/qv63o6bQ?game_version=retail&__debug__=true
|
||||
const url = new URL(`${WAGO_BASE_URL}/addons/${addonId}`);
|
||||
return await this._cachingService.transaction(
|
||||
url.toString(),
|
||||
() => this._circuitBreaker.getJson<WagoAddon>(url, this.getRequestHeaders()),
|
||||
WAGO_DETAILS_CACHE_TIME_SEC
|
||||
);
|
||||
}
|
||||
|
||||
private toSearchResult(item: WagoSearchResponseItem): AddonSearchResult {
|
||||
const releaseTypes = Object.keys(item.releases);
|
||||
const searchResultFiles: AddonSearchResultFile[] = [];
|
||||
for (const type of releaseTypes) {
|
||||
searchResultFiles.push(this.toSearchResultFile(item.releases[type], type as WagoStability));
|
||||
}
|
||||
|
||||
return {
|
||||
author: "",
|
||||
externalId: item.id,
|
||||
externalUrl: "",
|
||||
name: item.display_name,
|
||||
providerName: this.name,
|
||||
thumbnailUrl: item.thumbnail_image,
|
||||
downloadCount: 0,
|
||||
files: searchResultFiles,
|
||||
releasedAt: new Date(),
|
||||
summary: item.summary,
|
||||
};
|
||||
}
|
||||
|
||||
private toSearchResultFile(release: WagoSearchResponseRelease, stability: WagoStability): AddonSearchResultFile {
|
||||
return {
|
||||
channelType: this.getAddonChannelType(stability),
|
||||
downloadUrl: release.download_link,
|
||||
folders: [],
|
||||
gameVersion: "",
|
||||
releaseDate: new Date(release.created_at),
|
||||
version: release.label,
|
||||
dependencies: [],
|
||||
};
|
||||
}
|
||||
|
||||
private getAddonChannelType(stability: WagoStability): AddonChannelType {
|
||||
switch (stability) {
|
||||
case "alpha":
|
||||
return AddonChannelType.Alpha;
|
||||
case "beta":
|
||||
return AddonChannelType.Beta;
|
||||
case "stable":
|
||||
default:
|
||||
return AddonChannelType.Stable;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the wago friendly name for our addon channel
|
||||
private getStability(channelType: AddonChannelType): WagoStability {
|
||||
switch (channelType) {
|
||||
case AddonChannelType.Alpha:
|
||||
return "alpha";
|
||||
case AddonChannelType.Beta:
|
||||
return "beta";
|
||||
case AddonChannelType.Stable:
|
||||
default:
|
||||
return "stable";
|
||||
}
|
||||
}
|
||||
|
||||
// The wago name for the client type
|
||||
private getGameVersion(clientType: WowClientType): WagoGameVersion {
|
||||
const clientGroup = this._warcraftService.getClientGroup(clientType);
|
||||
@@ -105,4 +291,17 @@ export class WagoAddonProvider extends AddonProvider {
|
||||
const scanResults: AppWowUpScanResult[] = await this._electronService.invoke("wowup-get-scan-results", filePaths);
|
||||
return scanResults;
|
||||
};
|
||||
|
||||
private onWagoTokenReceived = (evt, token) => {
|
||||
console.debug(`[wago] onWagoTokenReceived`, token);
|
||||
this._apiToken = token;
|
||||
};
|
||||
|
||||
private getRequestHeaders(): {
|
||||
[header: string]: string | string[];
|
||||
} {
|
||||
return {
|
||||
Authorization: `Bearer ${this._apiToken}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="main">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<div *ngIf="sessionService.adSpace$ | async" class="ad-space text-1">
|
||||
<div *ngIf="sessionService.adSpace$ | async" class="ad-space text-1 bg-secondary-3">
|
||||
<div class="ad-details p-3">
|
||||
<div class="center-col">
|
||||
<div>
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="ad">
|
||||
<app-webview></app-webview>
|
||||
<app-webview *ngFor="let params of adPageParams" [options]="params"></app-webview>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
ZOOM_FACTOR_KEY,
|
||||
} from "../common/constants";
|
||||
import { Addon } from "../common/entities/addon";
|
||||
import { AppUpdateState, MenuConfig, SystemTrayConfig } from "../common/wowup/models";
|
||||
import { AdPageOptions, AppUpdateState, MenuConfig, SystemTrayConfig } from "../common/wowup/models";
|
||||
import { AppConfig } from "../environments/environment";
|
||||
import { InstallFromUrlDialogComponent } from "./components/addons/install-from-url-dialog/install-from-url-dialog.component";
|
||||
import { AlertDialogComponent } from "./components/common/alert-dialog/alert-dialog.component";
|
||||
@@ -83,6 +83,7 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
|
||||
public quitEnabled?: boolean;
|
||||
public showPreLoad = true;
|
||||
public adPageParams: AdPageOptions[] = [];
|
||||
|
||||
public constructor(
|
||||
private _addonService: AddonService,
|
||||
@@ -135,6 +136,17 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.sessionService.adSpace$.subscribe((enabled) => {
|
||||
if (enabled) {
|
||||
const providers = this._addonService.getAdRequiredProviders();
|
||||
this.adPageParams = providers
|
||||
.map((provider) => provider.getAdPageParams())
|
||||
.filter((param) => param !== undefined);
|
||||
} else {
|
||||
this.adPageParams = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
@@ -215,9 +227,6 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
// TODO this is driven by provider
|
||||
this.sessionService.enableAdSpace(true);
|
||||
|
||||
from(this.createAppMenu())
|
||||
.pipe(
|
||||
first(),
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<div mat-dialog-title class="addon-detail-view">
|
||||
<div class="row align-items-start mb-1">
|
||||
<div class="row justify-content-center bg-secondary-4 mr-3 icon flex-shrink-0"
|
||||
<div
|
||||
class="row justify-content-center bg-secondary-4 mr-3 icon flex-shrink-0"
|
||||
[matTooltip]="('DIALOGS.ADDON_DETAILS.ADDON_ID_PREFIX' | translate) + displayExternalId"
|
||||
[cdkCopyToClipboard]="fullExternalId" (click)="onClickExternalId()">
|
||||
<div *ngIf="hasIconUrl === false" class=" text-3">
|
||||
[cdkCopyToClipboard]="fullExternalId"
|
||||
(click)="onClickExternalId()"
|
||||
>
|
||||
<div *ngIf="hasIconUrl === false" class="text-3">
|
||||
{{ thumbnailLetter }}
|
||||
</div>
|
||||
|
||||
@@ -12,30 +15,34 @@
|
||||
|
||||
<div class="flex-grow-1 mr-1">
|
||||
<h2 class="m-0 title">{{ title }}</h2>
|
||||
<h3 class="m-0">{{ 'DIALOGS.ADDON_DETAILS.BY_AUTHOR' | translate:{ authorName: subtitle } }}</h3>
|
||||
<h3 class="m-0">{{ "DIALOGS.ADDON_DETAILS.BY_AUTHOR" | translate: { authorName: subtitle } }}</h3>
|
||||
<h4 class="m-0 text-2">{{ version }}</h4>
|
||||
</div>
|
||||
<mat-icon class="close-icon" color="accent" [mat-dialog-close]="true" [ngStyle]="{ cursor: 'pointer' }"
|
||||
svgIcon="fas:times">
|
||||
<mat-icon
|
||||
class="close-icon"
|
||||
color="accent"
|
||||
[mat-dialog-close]="true"
|
||||
[ngStyle]="{ cursor: 'pointer' }"
|
||||
svgIcon="fas:times"
|
||||
>
|
||||
</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="row align-items-start">
|
||||
</div>
|
||||
<div class="row align-items-start"></div>
|
||||
|
||||
<div *ngIf="hasFundingLinks" class="funding-link-container p-1">
|
||||
<h3 class="m-0">{{ 'DIALOGS.ADDON_DETAILS.FUNDING_LINK_TITLE' | translate }}</h3>
|
||||
<h3 class="m-0">{{ "DIALOGS.ADDON_DETAILS.FUNDING_LINK_TITLE" | translate }}</h3>
|
||||
<div class="row align-items-center">
|
||||
<app-funding-button *ngFor="let link of fundingLinks" [funding]="link"></app-funding-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MISSING DEPENDENCIES -->
|
||||
<div *ngIf="isUnknownProvider && isMissingUnknownDependencies">
|
||||
<h3>{{'DIALOGS.ADDON_DETAILS.MISSING_DEPENDENCIES' | translate}}</h3>
|
||||
<h3>{{ "DIALOGS.ADDON_DETAILS.MISSING_DEPENDENCIES" | translate }}</h3>
|
||||
<ul>
|
||||
<li *ngFor="let dependency of missingDependencies">{{dependency}}</li>
|
||||
<li *ngFor="let dependency of missingDependencies">{{ dependency }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- DEPENDENCIES -->
|
||||
@@ -46,28 +53,36 @@
|
||||
</span>
|
||||
</div>
|
||||
<!-- TABS -->
|
||||
<mat-tab-group #tabs *ngIf="isUnknownProvider === false" class="scroller" [selectedIndex]="selectedTabIndex"
|
||||
(selectedTabChange)="onSelectedTabChange($event)">
|
||||
<mat-tab-group
|
||||
#tabs
|
||||
*ngIf="isUnknownProvider === false"
|
||||
class="scroller"
|
||||
[selectedIndex]="selectedTabIndex"
|
||||
(selectedTabChange)="onSelectedTabChange($event)"
|
||||
>
|
||||
<!-- SUMMARY -->
|
||||
<mat-tab [label]="'DIALOGS.ADDON_DETAILS.DESCRIPTION_TAB' | translate">
|
||||
<app-progress-spinner *ngIf="fetchingFullDescription === true"></app-progress-spinner>
|
||||
<div #descriptionContainer class="markdown-body addon-summary text-1 mt-3" [innerHtml]="description$ | async">
|
||||
</div>
|
||||
<div
|
||||
#descriptionContainer
|
||||
class="markdown-body addon-summary text-1 mt-3"
|
||||
[innerHtml]="description$ | async"
|
||||
></div>
|
||||
</mat-tab>
|
||||
<!-- CHANGELOG -->
|
||||
<mat-tab *ngIf="canShowChangelog === true" [label]="'DIALOGS.ADDON_DETAILS.CHANGELOG_TAB' | translate">
|
||||
<app-progress-spinner *ngIf="fetchingChangelog === true"></app-progress-spinner>
|
||||
<div *ngIf="fetchingChangelog === false && hasChangeLog === false" class="mt-3">
|
||||
{{'DIALOGS.ADDON_DETAILS.NO_CHANGELOG_TEXT' |
|
||||
translate}}</div>
|
||||
{{ "DIALOGS.ADDON_DETAILS.NO_CHANGELOG_TEXT" | translate }}
|
||||
</div>
|
||||
<div #changelogContainer class="markdown-body addon-changelog text-1 mt-3" [innerHTML]="changelog$ | async"></div>
|
||||
</mat-tab>
|
||||
<!-- SCREENSHOTS -->
|
||||
<mat-tab *ngIf="previewItems.length > 0" [label]="'DIALOGS.ADDON_DETAILS.IMAGES_TAB' | translate">
|
||||
<mat-grid-list class="image-grid pt-3" cols="4" rowHeight="1:1" gutterSize="3">
|
||||
<mat-grid-tile *ngFor="let image of previewItems; index as i">
|
||||
<div class="image-thumb-container ">
|
||||
<img class="image-thumb mat-elevation-z8" [src]="image.data.thumb" [lightbox]="i">
|
||||
<div class="image-thumb-container">
|
||||
<img class="image-thumb mat-elevation-z8" [src]="image.data.thumb" [lightbox]="i" />
|
||||
</div>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
@@ -76,17 +91,27 @@
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions *ngIf="isUnknownProvider === false">
|
||||
<div class="row w-100">
|
||||
<button *ngIf="showRemoveButton" mat-button color="warn" (click)="onClickRemoveAddon()"> {{
|
||||
"PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.REMOVE_ADDON_BUTTON" | translate }}</button>
|
||||
<button *ngIf="showRemoveButton" mat-button color="warn" (click)="onClickRemoveAddon()">
|
||||
{{ "PAGES.MY_ADDONS.ADDON_CONTEXT_MENU.REMOVE_ADDON_BUTTON" | translate }}
|
||||
</button>
|
||||
<div class="flex-grow-1"></div>
|
||||
<a #providerLink mat-button class="mr-3 text-1" appExternalLink [href]="externalUrl"
|
||||
[matTooltip]="'DIALOGS.ADDON_DETAILS.VIEW_IN_BROWSER_BUTTON' | translate">{{
|
||||
"DIALOGS.ADDON_DETAILS.VIEW_ON_PROVIDER_PREFIX" | translate }}
|
||||
<a
|
||||
*ngIf="externalUrl !== 'UNKNOWN'"
|
||||
#providerLink
|
||||
mat-button
|
||||
class="mr-3 text-1"
|
||||
appExternalLink
|
||||
[href]="externalUrl"
|
||||
[matTooltip]="'DIALOGS.ADDON_DETAILS.VIEW_IN_BROWSER_BUTTON' | translate"
|
||||
>{{ "DIALOGS.ADDON_DETAILS.VIEW_ON_PROVIDER_PREFIX" | translate }}
|
||||
{{ provider }}
|
||||
</a>
|
||||
<app-addon-install-button *ngIf="showInstallButton" [addonSearchResult]="model.searchResult"
|
||||
(onViewUpdated)="onInstallUpdated()">
|
||||
<app-addon-install-button
|
||||
*ngIf="showInstallButton"
|
||||
[addonSearchResult]="model.searchResult"
|
||||
(onViewUpdated)="onInstallUpdated()"
|
||||
>
|
||||
</app-addon-install-button>
|
||||
<app-addon-update-button *ngIf="showUpdateButton" [listItem]="model.listItem"></app-addon-update-button>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
||||
</mat-dialog-actions>
|
||||
|
||||
@@ -20,7 +20,6 @@ export class OptionsAddonSectionComponent implements OnInit {
|
||||
public ngOnInit(): void {
|
||||
this.addonProviderStates = filter(this._addonService.getAddonProviderStates(), (provider) => provider.canEdit);
|
||||
this.enabledAddonProviders.setValue(this.getEnabledProviderNames());
|
||||
console.debug("addonProviderStates", this.addonProviderStates);
|
||||
}
|
||||
|
||||
public onProviderStateSelectionChange(event: MatSelectionListChange): void {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Directive, ElementRef, OnInit } from "@angular/core";
|
||||
import { Directive, ElementRef, Input, OnDestroy, OnInit } from "@angular/core";
|
||||
import { nanoid } from "nanoid";
|
||||
import { AdPageOptions } from "../../common/wowup/models";
|
||||
import { FileService } from "../services/files/file.service";
|
||||
|
||||
@Directive({
|
||||
selector: "app-webview",
|
||||
})
|
||||
export class WebviewComponent implements OnInit {
|
||||
// TODO add input URL
|
||||
// TODO add input config object
|
||||
export class WebviewComponent implements OnInit, OnDestroy {
|
||||
@Input("options") options: AdPageOptions;
|
||||
|
||||
private _tag: Electron.WebviewTag;
|
||||
private _id: string = nanoid();
|
||||
@@ -21,24 +21,37 @@ export class WebviewComponent implements OnInit {
|
||||
this.initWebview(this._element).catch((e) => console.error(e));
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// Clean up the webview element
|
||||
if (this._tag) {
|
||||
if (this._tag.isDevToolsOpened()) {
|
||||
this._tag.closeDevTools();
|
||||
}
|
||||
this._tag = undefined;
|
||||
}
|
||||
|
||||
this._element.nativeElement.innerHTML = 0;
|
||||
}
|
||||
|
||||
private async initWebview(element: ElementRef) {
|
||||
// ad container requires a 'normal' UA
|
||||
const userAgent = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`;
|
||||
const preloadPath = await this._fileService.getAssetFilePath("preload/wago.js");
|
||||
console.log("preloadPath", preloadPath);
|
||||
const pageReferrer = this.options.referrer ? `httpreferrer="${this.options.referrer}"` : "";
|
||||
const userAgent = this.options.userAgent ? `useragent="${this.options.userAgent}"` : "";
|
||||
const preload = this.options.preloadFilePath
|
||||
? `preload="${await this._fileService.getAssetFilePath(this.options.preloadFilePath)}"`
|
||||
: "";
|
||||
|
||||
const placeholder = document.createElement("div");
|
||||
placeholder.innerHTML = `
|
||||
<webview id="${this._id}"
|
||||
src="https://addons.wago.io/wowup_ad"
|
||||
httpreferrer="https://wago.io"
|
||||
src="${this.options.pageUrl}"
|
||||
${pageReferrer}
|
||||
style="width: 100%; height: 100%;"
|
||||
nodeintegration="false"
|
||||
nodeintegrationinsubframes="false"
|
||||
plugins="false"
|
||||
allowpopups="false"
|
||||
preload="${preloadPath}"
|
||||
useragent="${userAgent}">
|
||||
${preload}
|
||||
${userAgent}>
|
||||
</webview>`;
|
||||
|
||||
this._tag = placeholder.firstElementChild as Electron.WebviewTag;
|
||||
@@ -50,6 +63,6 @@ export class WebviewComponent implements OnInit {
|
||||
private onWebviewReady = () => {
|
||||
console.debug("onWebviewReady", this._tag);
|
||||
this._tag.removeEventListener("dom-ready", this.onWebviewReady);
|
||||
this._tag.openDevTools();
|
||||
// this._tag.openDevTools();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ export class AddonService {
|
||||
private readonly _searchErrorSrc = new Subject<GenericProviderError>();
|
||||
private readonly _installQueue = new Subject<InstallQueueItem>();
|
||||
private readonly _anyUpdatesAvailableSrc = new BehaviorSubject<boolean>(false);
|
||||
private readonly _addonProviderChangeSrc = new Subject<AddonProvider>();
|
||||
|
||||
private _activeInstalls: AddonUpdateEvent[] = [];
|
||||
private _subscriptions: Subscription[] = [];
|
||||
@@ -112,6 +113,7 @@ export class AddonService {
|
||||
public readonly scanError$ = this._scanErrorSrc.asObservable();
|
||||
public readonly searchError$ = this._searchErrorSrc.asObservable();
|
||||
public readonly anyUpdatesAvailable$ = this._anyUpdatesAvailableSrc.asObservable();
|
||||
public readonly addonProviderChange$ = this._addonProviderChangeSrc.asObservable();
|
||||
|
||||
public constructor(
|
||||
private _addonStorage: AddonStorageService,
|
||||
@@ -126,6 +128,7 @@ export class AddonService {
|
||||
) {
|
||||
// Create our base set of addon providers
|
||||
this._addonProviders = addonProviderFactory.getProviders();
|
||||
console.debug("_addonProviders", this._addonProviders);
|
||||
|
||||
// This should keep the current update queue state snapshot up to date
|
||||
const addonInstalledSub = this.addonInstalled$
|
||||
@@ -1831,11 +1834,14 @@ export class AddonService {
|
||||
return !!this.getByExternalId(externalId, providerName, installation.id);
|
||||
}
|
||||
|
||||
// TODO move this to a different service
|
||||
public setProviderEnabled(providerName: string, enabled: boolean): void {
|
||||
const provider = this.getProvider(providerName);
|
||||
if (provider) {
|
||||
provider.enabled = enabled;
|
||||
}
|
||||
|
||||
this._addonProviderChangeSrc.next(provider);
|
||||
}
|
||||
|
||||
private getProvider(providerName: string): AddonProvider | undefined {
|
||||
@@ -2018,6 +2024,10 @@ export class AddonService {
|
||||
return _.filter(this._addonProviders, (provider) => provider.enabled);
|
||||
}
|
||||
|
||||
public getAdRequiredProviders(): AddonProvider[] {
|
||||
return this.getEnabledAddonProviders().filter((provider) => provider.adRequired);
|
||||
}
|
||||
|
||||
private trackInstallAction(installType: InstallType, addon: Addon) {
|
||||
this._analyticsService.trackAction(USER_ACTION_ADDON_INSTALL, {
|
||||
clientType: getEnumName(WowClientType, addon.clientType),
|
||||
|
||||
@@ -10,6 +10,7 @@ import { WarcraftInstallationService } from "../warcraft/warcraft-installation.s
|
||||
import { ColumnState } from "../../models/wowup/column-state";
|
||||
import { map } from "rxjs/operators";
|
||||
import { WowUpAccountService } from "../wowup/wowup-account.service";
|
||||
import { AddonService } from "../addons/addon.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
@@ -55,7 +56,8 @@ export class SessionService {
|
||||
public constructor(
|
||||
private _warcraftInstallationService: WarcraftInstallationService,
|
||||
private _preferenceStorageService: PreferenceStorageService,
|
||||
private _wowUpAccountService: WowUpAccountService
|
||||
private _wowUpAccountService: WowUpAccountService,
|
||||
private _addonService: AddonService
|
||||
) {
|
||||
this._selectedDetailTabType =
|
||||
this._preferenceStorageService.getObject<DetailsTabType>(SELECTED_DETAILS_TAB_KEY) || "description";
|
||||
@@ -63,6 +65,17 @@ export class SessionService {
|
||||
this._warcraftInstallationService.wowInstallations$.subscribe((installations) =>
|
||||
this.onWowInstallationsChange(installations)
|
||||
);
|
||||
|
||||
this._addonService.addonProviderChange$.subscribe((provider) => {
|
||||
this.updateAdSpace();
|
||||
});
|
||||
|
||||
this.updateAdSpace();
|
||||
}
|
||||
|
||||
private updateAdSpace() {
|
||||
const allProviders = this._addonService.getEnabledAddonProviders();
|
||||
this._adSpaceSrc.next(allProviders.findIndex((p) => p.adRequired) !== -1);
|
||||
}
|
||||
|
||||
public get wowUpAuthToken(): string {
|
||||
@@ -93,10 +106,6 @@ export class SessionService {
|
||||
this._addonsChangedSrc.next(true);
|
||||
}
|
||||
|
||||
public enableAdSpace(enabled: boolean): void {
|
||||
this._adSpaceSrc.next(enabled);
|
||||
}
|
||||
|
||||
public getSelectedDetailsTab(): DetailsTabType {
|
||||
return this._selectedDetailTabType;
|
||||
}
|
||||
|
||||
3
wowup-electron/src/common/wowup.d.ts
vendored
3
wowup-electron/src/common/wowup.d.ts
vendored
@@ -88,7 +88,8 @@ declare type RendererChannels =
|
||||
| "base64-encode"
|
||||
| "base64-decode"
|
||||
| "set-release-channel"
|
||||
| "zip-list-files";
|
||||
| "zip-list-files"
|
||||
| "wago-token-received";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
||||
@@ -131,3 +131,11 @@ export interface AddonUpdatePushNotification extends PushNotificationData {
|
||||
addonName: string;
|
||||
addonId: string;
|
||||
}
|
||||
|
||||
export interface AdPageOptions {
|
||||
pageUrl: string;
|
||||
referrer?: string;
|
||||
userAgent?: string;
|
||||
preloadFilePath?: string;
|
||||
explanationKey?: string; // locale key of the translated explanation of this ad
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user