Skip to content

Commit

Permalink
updated special plugin lists
Browse files Browse the repository at this point in the history
  • Loading branch information
bwp91 committed Feb 11, 2024
1 parent 10bbcab commit edc6ff5
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ All notable changes to homebridge-config-ui-x will be documented in this file.
- add wiki change request issue template
- removed force of earlier version of `bonjour-service` as a fix has been implemented in latest version
- updated release drafter template so releases do not start with a `v`
- updated special plugin lists

## 4.55.1 (2024-01-07)

Expand Down
86 changes: 48 additions & 38 deletions src/modules/plugins/plugins.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,17 @@ export class PluginsService {
// npm package cache
private npmPackage: HomebridgePlugin;

// verified plugins cache
// plugin list caches
private verifiedPlugins: string[] = [];
private verifiedPluginsIcons: { [key: string]: string } = {};
private verifiedPluginsIconsPrefix = 'https://raw.githubusercontent.com/homebridge/verified/latest/';
private verifiedPlusPlugins: string[] = [];
private pluginIcons: { [key: string]: string } = {};
private pluginListsRepoUrl = 'https://raw.githubusercontent.com/homebridge/verified/latest/';
private hiddenPlugins: string[] = [];

private verifiedPluginsJson = 'https://raw.githubusercontent.com/homebridge/verified/latest/verified-plugins.json';
private verifiedPluginsIconsJson = 'https://raw.githubusercontent.com/homebridge/verified/latest/plugin-icons.json';
private verifiedPluginsJson = `${this.pluginListsRepoUrl}verified-plugins.json`;
private verifiedPlusPluginsJson = `${this.pluginListsRepoUrl}verified-plus-plugins.json`;
private pluginIconsJson = `${this.pluginListsRepoUrl}plugin-icons.json`;
private hiddenPluginsJson = `${this.pluginListsRepoUrl}hidden-plugins.json`;

// misc schemas
private miscSchemas = {
Expand All @@ -96,18 +100,7 @@ export class PluginsService {
// create a cache for storing plugin alias
private pluginAliasCache = new NodeCache({ stdTTL: 86400 });

private verifiedPluginsRetryTimeout: NodeJS.Timeout;

// these plugins are legacy Homebridge UI plugins / forks of this UI and will cause conflicts
// or have post install scripts that alter the users system without user interaction
private searchResultBlacklist = [
'homebridge-config-ui',
'homebridge-config-ui-rdp',
'homebridge-rocket-smart-home-ui',
'homebridge-ui',
'homebridge-to-hoobs',
'homebridge-server',
];
private specialPluginsRetryTimeout: NodeJS.Timeout;

/**
* Define the alias / type some plugins without a schema where the extract method does not work
Expand Down Expand Up @@ -144,10 +137,10 @@ export class PluginsService {
});

// initial verified plugins load
this.loadVerifiedPluginsList();
this.loadSpecialPluginsLists();

// update the verified plugins list every 12 hours
setInterval(this.loadVerifiedPluginsList.bind(this), 60000 * 60 * 12);
setInterval(this.loadSpecialPluginsLists.bind(this), 60000 * 60 * 12);
}

/**
Expand Down Expand Up @@ -273,7 +266,7 @@ export class PluginsService {

const result: HomebridgePlugin[] = searchResults.objects
.filter(x => x.package.name.indexOf('homebridge-') === 0 || this.isScopedPlugin(x.package.name))
.filter(x => !this.searchResultBlacklist.includes(x.package.name))
.filter(x => !this.hiddenPlugins.includes(x.package.name))
.map((pkg) => {
let plugin: HomebridgePlugin = {
name: pkg.package.name,
Expand All @@ -298,16 +291,17 @@ export class PluginsService {
plugin.links = pkg.package.links;
plugin.author = (pkg.package.publisher) ? pkg.package.publisher.username : null;
plugin.verifiedPlugin = this.verifiedPlugins.includes(pkg.package.name);
plugin.icon = this.verifiedPluginsIcons[pkg.package.name]
? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pkg.package.name]}`
plugin.verifiedPlusPlugin = this.verifiedPlusPlugins.includes(pkg.package.name);
plugin.icon = this.pluginIcons[pkg.package.name]
? `${this.pluginListsRepoUrl}${this.pluginIcons[pkg.package.name]}`
: null;
return plugin;
});

if (
!result.length
&& (query.indexOf('homebridge-') === 0 || this.isScopedPlugin(query))
&& !this.searchResultBlacklist.includes(query.toLowerCase())
&& !this.hiddenPlugins.includes(query.toLowerCase())
) {
try {
return await this.searchNpmRegistrySingle(query.toLowerCase());
Expand All @@ -316,7 +310,7 @@ export class PluginsService {
}
}

return orderBy(result, ['verifiedPlugin'], ['desc']);
return orderBy(result, ['verifiedPlusPlugin', 'verifiedPlugin'], ['desc', 'desc']);
}

/**
Expand Down Expand Up @@ -357,7 +351,8 @@ export class PluginsService {
description: (pkg.description) ?
pkg.description.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '').trim() : pkg.name,
verifiedPlugin: this.verifiedPlugins.includes(pkg.name),
icon: this.verifiedPluginsIcons[pkg.name],
verifiedPlusPlugin: this.verifiedPlusPlugins.includes(pkg.name),
icon: this.pluginIcons[pkg.name],
} as HomebridgePlugin;

// it's not installed; finish building the response
Expand All @@ -373,8 +368,9 @@ export class PluginsService {
};
plugin.author = (pkg.maintainers.length) ? pkg.maintainers[0].name : null;
plugin.verifiedPlugin = this.verifiedPlugins.includes(pkg.name);
plugin.icon = this.verifiedPluginsIcons[pkg.name]
? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pkg.name]}`
plugin.verifiedPlusPlugin = this.verifiedPlusPlugins.includes(pkg.name);
plugin.icon = this.pluginIcons[pkg.name]
? `${this.pluginListsRepoUrl}${this.pluginIcons[pkg.name]}`
: null;

return [plugin];
Expand Down Expand Up @@ -1230,8 +1226,9 @@ export class PluginsService {
description: (pkgJson.description) ?
pkgJson.description.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '').trim() : pkgJson.name,
verifiedPlugin: this.verifiedPlugins.includes(pkgJson.name),
icon: this.verifiedPluginsIcons[pkgJson.name]
? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pkgJson.name]}`
verifiedPlusPlugin: this.verifiedPlusPlugins.includes(pkgJson.name),
icon: this.pluginIcons[pkgJson.name]
? `${this.pluginListsRepoUrl}${this.pluginIcons[pkgJson.name]}`
: null,
installedVersion: installPath ? (pkgJson.version || '0.0.1') : null,
globalInstall: (installPath !== this.configService.customPluginPath),
Expand All @@ -1240,7 +1237,7 @@ export class PluginsService {
};

// only verified plugins can show donation links
plugin.funding = plugin.verifiedPlugin ? pkgJson.funding : undefined;
plugin.funding = (plugin.verifiedPlugin || plugin.verifiedPlusPlugin) ? pkgJson.funding : undefined;

// if the plugin is private, do not attempt to query npm
if (pkgJson.private) {
Expand Down Expand Up @@ -1503,27 +1500,40 @@ export class PluginsService {
}

/**
* Loads the list of verified plugins from GitHub
* Loads the list of special plugins from GitHub
* This is verified plugins, verified plus plugins, plugin icons and hidden plugins
*/
private async loadVerifiedPluginsList() {
clearTimeout(this.verifiedPluginsRetryTimeout);
private async loadSpecialPluginsLists() {
clearTimeout(this.specialPluginsRetryTimeout);
try {
this.verifiedPlugins = (
await this.httpService.get(this.verifiedPluginsJson, {
httpsAgent: null,
}).toPromise()
).data;

this.verifiedPluginsIcons = (
await this.httpService.get(this.verifiedPluginsIconsJson, {
this.verifiedPlusPlugins = (
await this.httpService.get(this.verifiedPlusPluginsJson, {
httpsAgent: null,
}).toPromise()
).data;

this.pluginIcons = (
await this.httpService.get(this.pluginIconsJson, {
httpsAgent: null,
}).toPromise()
).data;

this.hiddenPlugins = (
await this.httpService.get(this.hiddenPluginsJson, {
httpsAgent: null,
}).toPromise()
).data;
} catch (e) {
this.logger.debug('Error when trying to get verified plugin list:', e.message);
this.logger.debug('Error when trying to get github plugin lists:', e.message);
// try again in 60 seconds
this.verifiedPluginsRetryTimeout = setTimeout(() => {
this.loadVerifiedPluginsList();
this.specialPluginsRetryTimeout = setTimeout(() => {
this.loadSpecialPluginsLists();
}, 60000);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/modules/plugins/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface HomebridgePlugin {
displayName?: string;
description?: string;
verifiedPlugin?: boolean;
verifiedPlusPlugin?: boolean;
icon?: string;
publicPackage?: boolean;
installedVersion?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ <h5 class="card-title mb-2 text-truncate">
</p>
<!-- // -->
<!-- plugin verified -->
<p class="card-text mb-2" *ngIf="plugin.verifiedPlugin">
<p class="card-text mb-2" *ngIf="plugin.verifiedPlugin || plugin.verifiedPlusPlugin">
<a href="javascript:void(0)" class="card-link green-text" (click)="openVerifiedModal()">
<i class="fas fa-fw fa-shield-alt fa-lg mr-1"></i>
<span class="grey-text">{{ 'plugins.donate.button_verified' | translate }}</span>
</a>
</p>
<!-- // -->
<!-- plugin not verified -->
<p class="card-text mb-2" *ngIf="!plugin.verifiedPlugin">
<p class="card-text mb-2" *ngIf="!plugin.verifiedPlugin && !plugin.verifiedPlusPlugin">
<a href="javascript:void(0)" class="card-link" (click)="openVerifiedModal()">
<i class="fas fa-fw fa-shield-alt fa-lg mr-1" style="opacity: 0.25;"></i>
<span class="grey-text">{{ 'plugins.donate.button_not_verified' | translate }}</span>
Expand All @@ -79,12 +79,12 @@ <h5 class="card-title mb-2 text-truncate">
<!-- // -->
<!-- plugin author and donate modal -->
<p class="card-text mb-2">
<a href="javascript:void(0)" class="card-link pink-text" *ngIf="plugin.verifiedPlugin && plugin.funding"
<a href="javascript:void(0)" class="card-link pink-text" *ngIf="(plugin.verifiedPlugin || plugin.verifiedPlusPlugin) && plugin.funding"
(click)="openFundingModal(plugin)">
<i class="fas fa-fw fa-heart fa-lg mr-1"></i>
<span class="grey-text">@{{ plugin.author }}</span>
</a>
<span class="grey-text" *ngIf="!plugin.verifiedPlugin || !plugin.funding">
<span class="grey-text" *ngIf="(plugin.verifiedPlugin || plugin.verifiedPlusPlugin) && plugin.funding">
<i class="fas fa-fw fa-heart fa-lg mr-1" style="opacity: 0.5;"></i>@{{ plugin.author }}
</span>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class PluginCardComponent implements OnInit {
size: 'lg',
backdrop: 'static',
});
if (this.plugin.verifiedPlugin) {
if (this.plugin.verifiedPlugin || this.plugin.verifiedPlusPlugin) {
ref.componentInstance.title = this.$translate.instant('plugins.manage.modal_verified_title');
ref.componentInstance.subtitle = this.$translate.instant('plugins.manage.modal_verified_subtitle', {
pluginName: this.plugin.displayName || this.plugin.name,
Expand Down

0 comments on commit edc6ff5

Please sign in to comment.