mirror of
https://github.com/WowUp/WowUp.git
synced 2026-04-22 06:49:05 -04:00
1861
wowup-electron/package-lock.json
generated
1861
wowup-electron/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@
|
||||
"electron:publish": "npm run lint && npm run build:prod && electron-builder build --publish always",
|
||||
"electron:publish:linux": "docker-compose -f linux-compose.yml up",
|
||||
"electron:publish:never": "npm run electron:build && electron-builder --publish never",
|
||||
"electron:publish:never:local": "npx electron-builder -c electron-builder-local.json --publish never ",
|
||||
"electron:publish:never:local": "npm run build:dev && npx electron-builder -c electron-builder-local.json --publish never ",
|
||||
"test": "ng test --watch=false",
|
||||
"test:watch": "ng test",
|
||||
"test:locales": "ng test --watch=false --include='src/locales.spec.ts'",
|
||||
@@ -55,13 +55,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/custom-webpack": "13.1.0",
|
||||
"@angular-devkit/build-angular": "13.2.4",
|
||||
"@angular-devkit/build-angular": "13.2.6",
|
||||
"@angular-eslint/builder": "13.1.0",
|
||||
"@angular-eslint/eslint-plugin": "13.1.0",
|
||||
"@angular-eslint/eslint-plugin-template": "13.1.0",
|
||||
"@angular-eslint/schematics": "13.1.0",
|
||||
"@angular-eslint/template-parser": "13.1.0",
|
||||
"@angular/cli": "13.2.4",
|
||||
"@angular/cli": "13.2.6",
|
||||
"@ngx-translate/core": "14.0.0",
|
||||
"@ngx-translate/http-loader": "7.0.0",
|
||||
"@types/adm-zip": "0.4.34",
|
||||
@@ -70,7 +70,7 @@
|
||||
"@types/globrex": "0.1.1",
|
||||
"@types/jasmine": "3.10.3",
|
||||
"@types/jasminewd2": "2.0.10",
|
||||
"@types/lodash": "4.14.178",
|
||||
"@types/lodash": "4.14.179",
|
||||
"@types/markdown-it": "12.2.3",
|
||||
"@types/mocha": "9.1.0",
|
||||
"@types/node": "16.11.10",
|
||||
@@ -79,22 +79,22 @@
|
||||
"@types/slug": "5.0.3",
|
||||
"@types/string-similarity": "4.0.0",
|
||||
"@types/uuid": "8.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "5.12.1",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "5.12.1",
|
||||
"@typescript-eslint/parser": "5.12.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.14.0",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "5.14.0",
|
||||
"@typescript-eslint/parser": "5.14.0",
|
||||
"chai": "4.3.6",
|
||||
"core-js": "3.21.1",
|
||||
"cross-env": "7.0.3",
|
||||
"del": "6.0.0",
|
||||
"dotenv": "16.0.0",
|
||||
"electron": "17.1.0",
|
||||
"electron-builder": "22.14.5",
|
||||
"electron": "17.1.2",
|
||||
"electron-builder": "22.14.13",
|
||||
"electron-notarize": "1.1.1",
|
||||
"electron-reload": "2.0.0-alpha.1",
|
||||
"eslint": "8.9.0",
|
||||
"eslint-config-prettier": "8.4.0",
|
||||
"eslint": "8.10.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-import": "2.25.4",
|
||||
"eslint-plugin-jsdoc": "37.9.4",
|
||||
"eslint-plugin-jsdoc": "38.0.0",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"flat": "5.0.2",
|
||||
"gulp": "4.0.2",
|
||||
@@ -109,8 +109,8 @@
|
||||
"karma-jasmine-html-reporter": "1.7.0",
|
||||
"mocha": "9.2.1",
|
||||
"node-addon-api": "4.3.0",
|
||||
"node-fetch": "3.2.0",
|
||||
"node-gyp": "8.4.1",
|
||||
"node-fetch": "3.2.2",
|
||||
"node-gyp": "9.0.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.5.1",
|
||||
"spectron": "19.0.0",
|
||||
@@ -123,17 +123,17 @@
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "13.2.3",
|
||||
"@angular/cdk": "13.2.3",
|
||||
"@angular/common": "13.2.3",
|
||||
"@angular/compiler": "13.2.3",
|
||||
"@angular/compiler-cli": "13.2.3",
|
||||
"@angular/core": "13.2.3",
|
||||
"@angular/forms": "13.2.3",
|
||||
"@angular/material": "13.2.3",
|
||||
"@angular/platform-browser": "13.2.3",
|
||||
"@angular/platform-browser-dynamic": "13.2.3",
|
||||
"@angular/router": "13.2.3",
|
||||
"@angular/animations": "13.2.6",
|
||||
"@angular/cdk": "13.2.6",
|
||||
"@angular/common": "13.2.6",
|
||||
"@angular/compiler": "13.2.6",
|
||||
"@angular/compiler-cli": "13.2.6",
|
||||
"@angular/core": "13.2.6",
|
||||
"@angular/forms": "13.2.6",
|
||||
"@angular/material": "13.2.6",
|
||||
"@angular/platform-browser": "13.2.6",
|
||||
"@angular/platform-browser-dynamic": "13.2.6",
|
||||
"@angular/router": "13.2.6",
|
||||
"@bbob/core": "2.8.0",
|
||||
"@bbob/html": "2.8.0",
|
||||
"@bbob/preset-html5": "2.8.0",
|
||||
@@ -143,7 +143,7 @@
|
||||
"@fortawesome/free-brands-svg-icons": "6.0.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.0.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.0.0",
|
||||
"@microsoft/applicationinsights-web": "2.7.3",
|
||||
"@microsoft/applicationinsights-web": "2.7.4",
|
||||
"adm-zip": "0.5.9",
|
||||
"ag-grid-angular": "27.0.0",
|
||||
"ag-grid-community": "27.0.1",
|
||||
@@ -160,7 +160,7 @@
|
||||
"messageformat": "2.3.0",
|
||||
"minimist": "1.2.5",
|
||||
"nanoid": "3.3.1",
|
||||
"ng-gallery": "6.0.0",
|
||||
"ng-gallery": "6.0.1",
|
||||
"ngx-translate-messageformat-compiler": "5.0.1",
|
||||
"node-cache": "5.1.2",
|
||||
"node-disk-info": "1.3.0",
|
||||
@@ -169,12 +169,12 @@
|
||||
"protobufjs": "6.11.2",
|
||||
"pushy-electron": "1.0.8",
|
||||
"rxjs": "7.5.4",
|
||||
"slug": "5.2.0",
|
||||
"slug": "5.3.0",
|
||||
"string-similarity": "4.0.4",
|
||||
"ts-custom-error": "3.2.0",
|
||||
"tslib": "2.3.1",
|
||||
"uuid": "8.3.2",
|
||||
"win-ca": "3.4.5",
|
||||
"win-ca": "3.5.0",
|
||||
"yauzl": "2.10.0",
|
||||
"zone.js": "0.11.4"
|
||||
},
|
||||
|
||||
@@ -49,6 +49,7 @@ import { strictFilter } from "../utils/array.utils";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
import { WarcraftService } from "../services/warcraft/warcraft.service";
|
||||
import { SensitiveStorageService } from "../services/storage/sensitive-storage.service";
|
||||
import { getWowClientGroup } from "../../common/warcraft";
|
||||
|
||||
interface ProtocolData {
|
||||
addonId: number;
|
||||
@@ -812,7 +813,9 @@ export class CurseAddonV2Provider extends AddonProvider {
|
||||
}
|
||||
|
||||
private getLatestFiles(result: CF2Addon, clientType: WowClientType): CF2File[] {
|
||||
const filtered = result.latestFiles.filter((latestFile) => this.isClientType(latestFile, clientType));
|
||||
const filtered = result.latestFiles.filter(
|
||||
(latestFile) => latestFile.exposeAsAlternative !== true && this.isClientType(latestFile, clientType)
|
||||
);
|
||||
return _.sortBy(filtered, (latestFile) => latestFile.id).reverse();
|
||||
}
|
||||
|
||||
@@ -1021,7 +1024,7 @@ export class CurseAddonV2Provider extends AddonProvider {
|
||||
}
|
||||
|
||||
private getCFGameVersionType(clientType: WowClientType): CF2WowGameVersionType {
|
||||
const clientGroup = this._warcraftService.getClientGroup(clientType);
|
||||
const clientGroup = getWowClientGroup(clientType);
|
||||
|
||||
switch (clientGroup) {
|
||||
case WowClientGroup.BurningCrusade:
|
||||
|
||||
@@ -26,6 +26,7 @@ import { WowInstallation } from "../../common/warcraft/wow-installation";
|
||||
import { convertMarkdown } from "../utils/markdown.utlils";
|
||||
import { strictFilterBy } from "../utils/array.utils";
|
||||
import { WarcraftService } from "../services/warcraft/warcraft.service";
|
||||
import { getWowClientGroup } from "../../common/warcraft";
|
||||
|
||||
type MetadataFlavor = "bcc" | "classic" | "mainline";
|
||||
|
||||
@@ -126,7 +127,7 @@ export class GitHubAddonProvider extends AddonProvider {
|
||||
searchResult: undefined,
|
||||
};
|
||||
|
||||
const clientGroup = this._warcraftService.getClientGroup(installation.clientType);
|
||||
const clientGroup = getWowClientGroup(installation.clientType);
|
||||
|
||||
try {
|
||||
const results = await this.getReleases(repoPath);
|
||||
|
||||
@@ -174,11 +174,11 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
|
||||
matches.push({ ...tukUiAddon });
|
||||
|
||||
const installedFolders = targetToc.tukUiProjectFolders ? targetToc.tukUiProjectFolders : tukUiAddon.name;
|
||||
const installedFolders = targetToc.tukUiProjectFolders ? targetToc.tukUiProjectFolders : addonFolder.name;
|
||||
|
||||
const installedFolderList = targetToc.tukUiProjectFolders
|
||||
? targetToc.tukUiProjectFolders.split(",").map((f) => f.trim())
|
||||
: [tukUiAddon.name];
|
||||
: [addonFolder.name];
|
||||
|
||||
addonFolder.matchingAddon = {
|
||||
autoUpdateEnabled: false,
|
||||
|
||||
@@ -24,6 +24,7 @@ import { getEnumName } from "../utils/enum.utils";
|
||||
import { convertMarkdown } from "../utils/markdown.utlils";
|
||||
import { AddonProvider, GetAllResult } from "./addon-provider";
|
||||
import { SourceRemovedAddonError } from "../errors";
|
||||
import { getWowClientGroup } from "../../common/warcraft";
|
||||
|
||||
declare type WagoGameVersion = "retail" | "classic" | "bc";
|
||||
declare type WagoStability = "stable" | "beta" | "alpha";
|
||||
@@ -643,7 +644,7 @@ export class WagoAddonProvider extends AddonProvider {
|
||||
|
||||
// The wago name for the client type
|
||||
private getGameVersion(clientType: WowClientType): WagoGameVersion {
|
||||
const clientGroup = this._warcraftService.getClientGroup(clientType);
|
||||
const clientGroup = getWowClientGroup(clientType);
|
||||
switch (clientGroup) {
|
||||
case WowClientGroup.BurningCrusade:
|
||||
return "bc";
|
||||
|
||||
@@ -3,13 +3,17 @@ import { from, Observable } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { ADDON_PROVIDER_HUB, IPC_WOWUP_GET_SCAN_RESULTS } from "../../common/constants";
|
||||
import { ADDON_PROVIDER_HUB, APP_PROTOCOL_NAME, IPC_WOWUP_GET_SCAN_RESULTS } from "../../common/constants";
|
||||
import { Addon } from "../../common/entities/addon";
|
||||
import { WowClientType } from "../../common/warcraft/wow-client-type";
|
||||
import { WowClientGroup, WowClientType } from "../../common/warcraft/wow-client-type";
|
||||
import { AddonCategory, AddonChannelType, WowUpScanResult } from "../../common/wowup/models";
|
||||
import { AppConfig } from "../../environments/environment";
|
||||
import { SourceRemovedAddonError } from "../errors";
|
||||
import { WowUpAddonReleaseRepresentation, WowUpAddonRepresentation } from "../models/wowup-api/addon-representations";
|
||||
import {
|
||||
AddonReleaseGameVersion,
|
||||
WowUpAddonReleaseRepresentation,
|
||||
WowUpAddonRepresentation,
|
||||
} from "../models/wowup-api/addon-representations";
|
||||
import {
|
||||
GetFeaturedAddonsResponse,
|
||||
WowUpGetAddonReleaseResponse,
|
||||
@@ -30,6 +34,12 @@ import { CircuitBreakerWrapper, NetworkService } from "../services/network/netwo
|
||||
import { getGameVersion } from "../utils/addon.utils";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider, GetAllBatchResult, GetAllResult } from "./addon-provider";
|
||||
import { ProtocolSearchResult } from "../models/wowup/protocol-search-result";
|
||||
|
||||
interface ProtocolData {
|
||||
addonId: string;
|
||||
releaseId: string;
|
||||
}
|
||||
|
||||
const API_URL = AppConfig.wowUpHubUrl;
|
||||
const FEATURED_ADDONS_CACHE_TTL_SEC = AppConfig.featuredAddonsCacheTimeSec;
|
||||
@@ -79,6 +89,55 @@ export class WowUpAddonProvider extends AddonProvider {
|
||||
return !addon.installedExternalReleaseId;
|
||||
}
|
||||
|
||||
public isValidProtocol(protocol: string): boolean {
|
||||
return protocol.toLowerCase().startsWith(`${APP_PROTOCOL_NAME}://`);
|
||||
}
|
||||
|
||||
public async searchProtocol(protocol: string): Promise<ProtocolSearchResult | undefined> {
|
||||
const protocolData = this.parseProtocol(protocol);
|
||||
if (!protocolData.addonId || !protocolData.releaseId) {
|
||||
throw new Error("Invalid protocol data");
|
||||
}
|
||||
|
||||
const addonResult = await this.getAddonById(protocolData.addonId);
|
||||
if (!addonResult) {
|
||||
throw new Error(`Failed to get addon data: ${protocolData.addonId}`);
|
||||
}
|
||||
|
||||
console.debug("addonResult", addonResult);
|
||||
|
||||
const addonFileResponse = await this.getReleaseById(protocolData.addonId, protocolData.releaseId);
|
||||
console.debug("targetFile", addonFileResponse);
|
||||
|
||||
if (!addonFileResponse) {
|
||||
throw new Error("Failed to get target file");
|
||||
}
|
||||
|
||||
const addonSearchResult = this.getSearchResultWithReleases(addonResult.addon, [addonFileResponse.release]);
|
||||
if (!addonSearchResult) {
|
||||
throw new Error("Addon search result not created");
|
||||
}
|
||||
|
||||
const searchResult: ProtocolSearchResult = {
|
||||
protocol,
|
||||
protocolAddonId: protocolData.addonId.toString(),
|
||||
protocolReleaseId: protocolData.releaseId.toString(),
|
||||
validClientGroups: _.map(addonFileResponse.release.game_versions, (gv) => this.getWowClientGroup(gv.game_type)),
|
||||
...addonSearchResult,
|
||||
};
|
||||
|
||||
console.debug("searchResult", searchResult);
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
private parseProtocol(protocol: string): ProtocolData {
|
||||
const url = new URL(protocol);
|
||||
return {
|
||||
addonId: url.searchParams.get("addonId") || "",
|
||||
releaseId: url.searchParams.get("releaseId") || "",
|
||||
};
|
||||
}
|
||||
|
||||
public async getAllBatch(installations: WowInstallation[], addonIds: string[]): Promise<GetAllBatchResult> {
|
||||
const batchResult: GetAllBatchResult = {
|
||||
errors: {},
|
||||
@@ -373,6 +432,13 @@ export class WowUpAddonProvider extends AddonProvider {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.getSearchResultFileWithVersion(release, matchingVersion);
|
||||
}
|
||||
|
||||
private getSearchResultFileWithVersion(
|
||||
release: WowUpAddonReleaseRepresentation,
|
||||
matchingVersion: AddonReleaseGameVersion
|
||||
): AddonSearchResultFile | undefined {
|
||||
const version = matchingVersion?.version || release.tag_name || "";
|
||||
|
||||
return {
|
||||
@@ -428,6 +494,37 @@ export class WowUpAddonProvider extends AddonProvider {
|
||||
};
|
||||
}
|
||||
|
||||
private getSearchResultWithReleases(
|
||||
representation: WowUpAddonRepresentation,
|
||||
releases: WowUpAddonReleaseRepresentation[]
|
||||
): AddonSearchResult | undefined {
|
||||
const searchResultFiles: AddonSearchResultFile[] = _.flatMap(releases, (release) =>
|
||||
_.map(release.game_versions, (gv) => this.getSearchResultFileWithVersion(release, gv))
|
||||
).filter((sr) => sr !== undefined);
|
||||
|
||||
if (searchResultFiles.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const name = _.first(searchResultFiles)?.title ?? representation.repository_name;
|
||||
const authors = _.first(searchResultFiles)?.authors ?? representation.owner_name ?? "";
|
||||
|
||||
return {
|
||||
author: authors,
|
||||
externalId: representation.id.toString(),
|
||||
externalUrl: `${AppConfig.wowUpWebsiteUrl}/addons/${representation.id}`,
|
||||
name,
|
||||
providerName: this.name,
|
||||
thumbnailUrl: representation.image_url || representation.owner_image_url || "",
|
||||
downloadCount: representation.total_download_count,
|
||||
files: searchResultFiles,
|
||||
releasedAt: new Date(),
|
||||
summary: representation.description,
|
||||
fundingLinks: [...(representation?.funding_links ?? [])],
|
||||
screenshotUrls: this.getScreenshotUrls(releases),
|
||||
};
|
||||
}
|
||||
|
||||
// Currently we only support images, so we filter for those
|
||||
private getScreenshotUrls(releases: WowUpAddonReleaseRepresentation[]): string[] {
|
||||
const urls = _.flatten(
|
||||
@@ -527,4 +624,15 @@ export class WowUpAddonProvider extends AddonProvider {
|
||||
return WowGameType.Retail;
|
||||
}
|
||||
}
|
||||
|
||||
private getWowClientGroup(gameType: WowGameType): WowClientGroup {
|
||||
switch (gameType) {
|
||||
case WowGameType.BurningCrusade:
|
||||
return WowClientGroup.BurningCrusade;
|
||||
case WowGameType.Classic:
|
||||
return WowClientGroup.Classic;
|
||||
case WowGameType.Retail:
|
||||
return WowClientGroup.Retail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
ConsentDialogComponent,
|
||||
ConsentDialogResult,
|
||||
} from "./components/common/consent-dialog/consent-dialog.component";
|
||||
import { WowUpProtocolService } from "./services/wowup/wowup-protocol.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-root",
|
||||
@@ -101,6 +102,7 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
private _warcraftInstallationService: WarcraftInstallationService,
|
||||
private _wowupAddonService: WowUpAddonService,
|
||||
private _zoomService: ZoomService,
|
||||
private _wowUpProtocolService: WowUpProtocolService,
|
||||
public electronService: ElectronService,
|
||||
public overlayContainer: OverlayContainer,
|
||||
public sessionService: SessionService,
|
||||
@@ -140,6 +142,8 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this._wowUpProtocolService.initialize();
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
|
||||
@@ -133,9 +133,18 @@ export class InstallFromProtocolDialogComponent implements OnInit, AfterViewInit
|
||||
|
||||
this.addon = searchResult;
|
||||
|
||||
this.validWowInstallations = await this._warcraftInstallationService.getWowInstallationsByClientTypes(
|
||||
searchResult.validClientTypes
|
||||
);
|
||||
if (Array.isArray(searchResult.validClientGroups)) {
|
||||
this.validWowInstallations = await this._warcraftInstallationService.getWowInstallationsByClientGroups(
|
||||
searchResult.validClientGroups
|
||||
);
|
||||
} else if (Array.isArray(searchResult.validClientTypes)) {
|
||||
this.validWowInstallations = await this._warcraftInstallationService.getWowInstallationsByClientTypes(
|
||||
searchResult.validClientTypes
|
||||
);
|
||||
} else {
|
||||
throw new Error("No valid clients found");
|
||||
}
|
||||
|
||||
if (this.validWowInstallations.length === 0) {
|
||||
this.error = ERROR_NO_VALID_WOW_INSTALLATIONS;
|
||||
return;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { WowClientGroup, WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { AddonSearchResult } from "./addon-search-result";
|
||||
|
||||
export interface ProtocolSearchResult extends AddonSearchResult {
|
||||
protocol: string;
|
||||
protocolAddonId?: string;
|
||||
protocolReleaseId?: string;
|
||||
validClientTypes: WowClientType[];
|
||||
validClientTypes?: WowClientType[];
|
||||
validClientGroups?: WowClientGroup[];
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { from, Subscription } from "rxjs";
|
||||
import { filter, first, map, switchMap } from "rxjs/operators";
|
||||
import { from, of, Subscription } from "rxjs";
|
||||
import { catchError, filter, first, map, switchMap, tap } from "rxjs/operators";
|
||||
|
||||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy } from "@angular/core";
|
||||
import { MatSnackBar } from "@angular/material/snack-bar";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
import {
|
||||
APP_PROTOCOL_NAME,
|
||||
CURSE_PROTOCOL_NAME,
|
||||
IPC_POWER_MONITOR_RESUME,
|
||||
IPC_POWER_MONITOR_UNLOCK,
|
||||
@@ -31,6 +30,7 @@ import { WarcraftInstallationService } from "../../services/warcraft/warcraft-in
|
||||
import { WowUpService } from "../../services/wowup/wowup.service";
|
||||
import { getProtocol } from "../../utils/string.utils";
|
||||
import { WowInstallation } from "../../../common/warcraft/wow-installation";
|
||||
import { WowUpProtocolService } from "../../services/wowup/wowup-protocol.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-home",
|
||||
@@ -62,7 +62,8 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
private _snackBarService: SnackbarService,
|
||||
private _cdRef: ChangeDetectorRef,
|
||||
private _warcraftInstallationService: WarcraftInstallationService,
|
||||
private _dialogFactory: DialogFactory
|
||||
private _dialogFactory: DialogFactory,
|
||||
private _wowUpProtocolService: WowUpProtocolService
|
||||
) {
|
||||
const wowInstalledSub = this._warcraftInstallationService.wowInstallations$.subscribe((installations) => {
|
||||
this.hasWowClient = installations.length > 0;
|
||||
@@ -70,8 +71,12 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
const customProtocolSub = this.electronService.customProtocol$
|
||||
.pipe(
|
||||
filter((protocol) => !!protocol),
|
||||
switchMap((protocol) => from(this.handleCustomProtocol(protocol)))
|
||||
filter((protocol) => getProtocol(protocol) === CURSE_PROTOCOL_NAME),
|
||||
tap((protocol) => this.handleAddonInstallProtocol(protocol)),
|
||||
catchError((e) => {
|
||||
console.error(e);
|
||||
return of(undefined);
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
@@ -85,25 +90,7 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
this._subscriptions.push(customProtocolSub, wowInstalledSub, scanErrorSub, scanUpdateSub, addonInstallErrorSub);
|
||||
}
|
||||
|
||||
private handleCustomProtocol = async (protocol: string): Promise<void> => {
|
||||
const protocolName = getProtocol(protocol);
|
||||
try {
|
||||
switch (protocolName) {
|
||||
case APP_PROTOCOL_NAME:
|
||||
break;
|
||||
case CURSE_PROTOCOL_NAME:
|
||||
await this.handleAddonInstallProtocol(protocol);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown protocol: ${protocol}`);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to handle protocol`, e);
|
||||
}
|
||||
};
|
||||
|
||||
private async handleAddonInstallProtocol(protocol: string) {
|
||||
private handleAddonInstallProtocol(protocol: string) {
|
||||
const dialog = this._dialogFactory.getDialog(InstallFromProtocolDialogComponent, {
|
||||
disableClose: true,
|
||||
data: {
|
||||
@@ -111,7 +98,7 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
},
|
||||
});
|
||||
|
||||
await dialog.afterClosed().toPromise();
|
||||
return dialog.afterClosed().pipe(first());
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
|
||||
@@ -108,7 +108,10 @@ export class MyAddonsComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
map((wowInstall) => wowInstall !== undefined)
|
||||
);
|
||||
|
||||
public readonly isBusy$ = this._isBusySrc.asObservable();
|
||||
public readonly isBusy$ = combineLatest([this._isBusySrc, this._addonService.syncing$]).pipe(
|
||||
map((vals) => _.some(vals))
|
||||
);
|
||||
|
||||
public readonly filterInput$ = this._filterInputSrc.asObservable();
|
||||
|
||||
public readonly rowData$ = combineLatest([this._baseRowDataSrc, this.filterInput$]).pipe(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { nanoid } from "nanoid";
|
||||
|
||||
import { Addon } from "../../../common/entities/addon";
|
||||
import { WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { getWowClientGroup } from "../../../common/warcraft";
|
||||
import { WowInstallation } from "../../../common/warcraft/wow-installation";
|
||||
import { getEnumName } from "../../utils/enum.utils";
|
||||
import { AddonStorageService } from "../storage/addon-storage.service";
|
||||
@@ -232,8 +233,8 @@ export class AddonBrokerService {
|
||||
}
|
||||
|
||||
private isSameClient(srcClient: WowClientType, targetClient: string) {
|
||||
const srcGroup = this._warcraftService.getClientGroup(srcClient);
|
||||
const targetGroup = this._warcraftService.getClientGroup(targetClient);
|
||||
const srcGroup = getWowClientGroup(srcClient);
|
||||
const targetGroup = getWowClientGroup(targetClient);
|
||||
|
||||
return srcGroup === targetGroup;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ export class AddonService {
|
||||
private readonly _installQueue = new Subject<InstallQueueItem>();
|
||||
private readonly _anyUpdatesAvailableSrc = new BehaviorSubject<boolean>(false);
|
||||
private readonly _addonProviderChangeSrc = new Subject<AddonProvider>();
|
||||
private readonly _syncingSrc = new BehaviorSubject<boolean>(false);
|
||||
|
||||
private _activeInstalls: AddonUpdateEvent[] = [];
|
||||
private _subscriptions: Subscription[] = [];
|
||||
@@ -132,6 +133,7 @@ export class AddonService {
|
||||
public readonly searchError$ = this._searchErrorSrc.asObservable();
|
||||
public readonly anyUpdatesAvailable$ = this._anyUpdatesAvailableSrc.asObservable();
|
||||
public readonly addonProviderChange$ = this._addonProviderChangeSrc.asObservable();
|
||||
public readonly syncing$ = this._syncingSrc.asObservable();
|
||||
|
||||
public constructor(
|
||||
private _addonStorage: AddonStorageService,
|
||||
@@ -1114,6 +1116,8 @@ export class AddonService {
|
||||
/** Iterate over all the installed WoW clients and attempt to check for addon updates */
|
||||
public async syncAllClients(): Promise<void> {
|
||||
console.debug("syncAllClients");
|
||||
this._syncingSrc.next(true);
|
||||
|
||||
const installations = await this._warcraftInstallationService.getWowInstallationsAsync();
|
||||
|
||||
try {
|
||||
@@ -1122,6 +1126,7 @@ export class AddonService {
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
this._syncingSrc.next(false);
|
||||
this._addonActionSrc.next({ type: "sync" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,6 @@ export class ElectronService {
|
||||
});
|
||||
|
||||
this.onRendererEvent(IPC_CUSTOM_PROTOCOL_RECEIVED, (evt, protocol: string) => {
|
||||
console.debug(IPC_CUSTOM_PROTOCOL_RECEIVED, protocol);
|
||||
this._customProtocolSrc.next(protocol);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as _ from "lodash";
|
||||
import { BehaviorSubject, from, Subject } from "rxjs";
|
||||
import { BehaviorSubject, combineLatest, from, Subject } from "rxjs";
|
||||
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
@@ -49,7 +49,9 @@ export class SessionService {
|
||||
public readonly wowUpAccountPushEnabled$ = this._wowUpAccountService.accountPushSrc.asObservable();
|
||||
public readonly myAddonsCompactVersion$ = this._myAddonsCompactVersionSrc.asObservable();
|
||||
public readonly adSpace$ = this._adSpaceSrc.asObservable(); // TODO this should be driven by the enabled providers
|
||||
public readonly enableControls$ = this._enableControlsSrc.asObservable();
|
||||
public readonly enableControls$ = combineLatest([this._enableControlsSrc, this._addonService.syncing$]).pipe(
|
||||
map(([enable, syncing]) => enable && !syncing)
|
||||
);
|
||||
public readonly debugAdFrame$ = new Subject<boolean>();
|
||||
public readonly currentTheme$ = this._currentThemeSrc.asObservable();
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
DEFAULT_CHANNEL_PREFERENCE_KEY_SUFFIX,
|
||||
WOW_INSTALLATIONS_KEY,
|
||||
} from "../../../common/constants";
|
||||
import { WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { WowClientGroup, WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { AddonChannelType } from "../../../common/wowup/models";
|
||||
import { WowInstallation } from "../../../common/warcraft/wow-installation";
|
||||
import { getEnumName } from "../../utils/enum.utils";
|
||||
@@ -20,6 +20,7 @@ import { ElectronService } from "../electron/electron.service";
|
||||
import { FileService } from "../files/file.service";
|
||||
import { PreferenceStorageService } from "../storage/preference-storage.service";
|
||||
import { WarcraftService } from "./warcraft.service";
|
||||
import { getWowClientFolderName, getWowClientGroup } from "../../../common/warcraft";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
@@ -108,6 +109,14 @@ export class WarcraftInstallationService {
|
||||
return _.filter(installations, (installation) => clientTypes.includes(installation.clientType));
|
||||
}
|
||||
|
||||
public async getWowInstallationsByClientGroups(clientGroups: WowClientGroup[]): Promise<WowInstallation[]> {
|
||||
const installations = await this.getWowInstallationsAsync();
|
||||
return _.filter(installations, (installation) => {
|
||||
const clientGroup = getWowClientGroup(installation.clientType);
|
||||
return clientGroups.includes(clientGroup);
|
||||
});
|
||||
}
|
||||
|
||||
public async setWowInstallations(wowInstallations: WowInstallation[]): Promise<void> {
|
||||
console.log(`Setting wow installations: ${wowInstallations.length}`);
|
||||
await this._preferenceStorageService.setAsync(WOW_INSTALLATIONS_KEY, wowInstallations);
|
||||
@@ -343,7 +352,7 @@ export class WarcraftInstallationService {
|
||||
}
|
||||
|
||||
private getFullProductPath(location: string, clientType: WowClientType): string {
|
||||
const clientFolderName = this._warcraftService.getClientFolderName(clientType);
|
||||
const clientFolderName = getWowClientFolderName(clientType);
|
||||
const executableName = this._warcraftService.getExecutableName(clientType);
|
||||
return path.join(location, clientFolderName, executableName);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Injectable } from "@angular/core";
|
||||
|
||||
import { ElectronService } from "../electron/electron.service";
|
||||
import * as constants from "../../../common/constants";
|
||||
import { WowClientGroup, WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { WowClientType } from "../../../common/warcraft/wow-client-type";
|
||||
import { InstalledProduct } from "../../models/warcraft/installed-product";
|
||||
import { AddonFolder } from "../../models/wowup/addon-folder";
|
||||
import { SelectItem } from "../../models/wowup/select-item";
|
||||
@@ -193,48 +193,6 @@ export class WarcraftService {
|
||||
return this._impl.getClientType(binaryPath);
|
||||
}
|
||||
|
||||
public getClientFolderName(clientType: WowClientType): string {
|
||||
switch (clientType) {
|
||||
case WowClientType.Retail:
|
||||
return constants.WOW_RETAIL_FOLDER;
|
||||
case WowClientType.ClassicEra:
|
||||
return constants.WOW_CLASSIC_ERA_FOLDER;
|
||||
case WowClientType.Classic:
|
||||
return constants.WOW_CLASSIC_FOLDER;
|
||||
case WowClientType.RetailPtr:
|
||||
return constants.WOW_RETAIL_PTR_FOLDER;
|
||||
case WowClientType.ClassicPtr:
|
||||
return constants.WOW_CLASSIC_PTR_FOLDER;
|
||||
case WowClientType.Beta:
|
||||
return constants.WOW_BETA_FOLDER;
|
||||
case WowClientType.ClassicBeta:
|
||||
return constants.WOW_CLASSIC_BETA_FOLDER;
|
||||
case WowClientType.ClassicEraPtr:
|
||||
return constants.WOW_CLASSIC_ERA_PTR_FOLDER;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public getClientGroup(clientType: string | WowClientType): WowClientGroup {
|
||||
const enumVal: WowClientType = typeof clientType === "string" ? WowClientType[clientType] : clientType;
|
||||
switch (enumVal) {
|
||||
case WowClientType.Beta:
|
||||
case WowClientType.Retail:
|
||||
case WowClientType.RetailPtr:
|
||||
return WowClientGroup.Retail;
|
||||
case WowClientType.ClassicEra:
|
||||
case WowClientType.ClassicEraPtr:
|
||||
return WowClientGroup.Classic;
|
||||
case WowClientType.Classic:
|
||||
case WowClientType.ClassicBeta:
|
||||
case WowClientType.ClassicPtr:
|
||||
return WowClientGroup.BurningCrusade;
|
||||
default:
|
||||
throw new Error(`unsupported client type: ${clientType}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old style preference key for a WoW client type
|
||||
* @deprecated
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { catchError, filter, first, of, switchMap, tap } from "rxjs";
|
||||
import { APP_PROTOCOL_NAME } from "../../../common/constants";
|
||||
import { InstallFromProtocolDialogComponent } from "../../components/addons/install-from-protocol-dialog/install-from-protocol-dialog.component";
|
||||
import { getProtocol, getProtocolParts } from "../../utils/string.utils";
|
||||
import { DialogFactory } from "../dialog/dialog.factory";
|
||||
import { ElectronService } from "../electron/electron.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class WowUpProtocolService {
|
||||
public constructor(private _dialogFactory: DialogFactory, private _electronService: ElectronService) {}
|
||||
|
||||
public initialize() {
|
||||
this._electronService.customProtocol$
|
||||
.pipe(
|
||||
tap((prt) => console.log("WowUpProtocolService", prt)),
|
||||
filter((prt) => getProtocol(prt) === APP_PROTOCOL_NAME && this.isInstallAction(prt)),
|
||||
switchMap((prt) => this.onInstallProtocol(prt)),
|
||||
catchError((e) => {
|
||||
console.error(e);
|
||||
return of(undefined);
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
public isInstallAction(protocol: string) {
|
||||
return getProtocolParts(protocol)[0] === "install";
|
||||
}
|
||||
|
||||
public onInstallProtocol(protocol: string) {
|
||||
console.log("onInstallProtocol", protocol);
|
||||
|
||||
const dialog = this._dialogFactory.getDialog(InstallFromProtocolDialogComponent, {
|
||||
disableClose: true,
|
||||
data: {
|
||||
protocol,
|
||||
},
|
||||
});
|
||||
|
||||
return dialog.afterClosed().pipe(first());
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,13 @@ export function getProtocol(arg: string): string | null {
|
||||
return match !== null && match.length > 1 ? match[1] : null;
|
||||
}
|
||||
|
||||
export function getProtocolParts(protocol: string) {
|
||||
return new URL(protocol).pathname
|
||||
.split("/")
|
||||
.filter((part) => !!part)
|
||||
.map((part) => part.toLowerCase());
|
||||
}
|
||||
|
||||
export function getRelativeDateFormat(value: string): [string, object | undefined] {
|
||||
if (!value) {
|
||||
return ["", undefined];
|
||||
|
||||
44
wowup-electron/src/common/warcraft/index.ts
Normal file
44
wowup-electron/src/common/warcraft/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import * as constants from "../constants";
|
||||
import { WowClientGroup, WowClientType } from "./wow-client-type";
|
||||
|
||||
export function getWowClientFolderName(clientType: WowClientType): string {
|
||||
switch (clientType) {
|
||||
case WowClientType.Retail:
|
||||
return constants.WOW_RETAIL_FOLDER;
|
||||
case WowClientType.ClassicEra:
|
||||
return constants.WOW_CLASSIC_ERA_FOLDER;
|
||||
case WowClientType.Classic:
|
||||
return constants.WOW_CLASSIC_FOLDER;
|
||||
case WowClientType.RetailPtr:
|
||||
return constants.WOW_RETAIL_PTR_FOLDER;
|
||||
case WowClientType.ClassicPtr:
|
||||
return constants.WOW_CLASSIC_PTR_FOLDER;
|
||||
case WowClientType.Beta:
|
||||
return constants.WOW_BETA_FOLDER;
|
||||
case WowClientType.ClassicBeta:
|
||||
return constants.WOW_CLASSIC_BETA_FOLDER;
|
||||
case WowClientType.ClassicEraPtr:
|
||||
return constants.WOW_CLASSIC_ERA_PTR_FOLDER;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function getWowClientGroup(clientType: string | WowClientType): WowClientGroup {
|
||||
const enumVal: WowClientType = typeof clientType === "string" ? WowClientType[clientType] : clientType;
|
||||
switch (enumVal) {
|
||||
case WowClientType.Beta:
|
||||
case WowClientType.Retail:
|
||||
case WowClientType.RetailPtr:
|
||||
return WowClientGroup.Retail;
|
||||
case WowClientType.ClassicEra:
|
||||
case WowClientType.ClassicEraPtr:
|
||||
return WowClientGroup.Classic;
|
||||
case WowClientType.Classic:
|
||||
case WowClientType.ClassicBeta:
|
||||
case WowClientType.ClassicPtr:
|
||||
return WowClientGroup.BurningCrusade;
|
||||
default:
|
||||
throw new Error(`unsupported client type: ${clientType}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user