mirror of
https://github.com/Llewellynvdm/nativefier.git
synced 2024-11-16 10:05:09 +00:00
b74c0bf959
* Convert app to strict typing + shared library * Fix new code post-merge * Remove extraneous lint ignores * Apply suggestions from code review Co-authored-by: Ronan Jouchet <ronan@jouchet.fr> * Fix prettier complaint * Dedupe eslint files * Fix some refs after merge * Fix clean:full command Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>
127 lines
3.5 KiB
TypeScript
127 lines
3.5 KiB
TypeScript
import * as path from 'path';
|
|
import { writeFile } from 'fs';
|
|
import { promisify } from 'util';
|
|
|
|
import gitCloud = require('gitcloud');
|
|
import pageIcon from 'page-icon';
|
|
|
|
import {
|
|
downloadFile,
|
|
DownloadResult,
|
|
getAllowedIconFormats,
|
|
getTempDir,
|
|
} from '../helpers/helpers';
|
|
import * as log from 'loglevel';
|
|
|
|
const writeFileAsync = promisify(writeFile);
|
|
|
|
const GITCLOUD_SPACE_DELIMITER = '-';
|
|
const GITCLOUD_URL = 'https://nativefier.github.io/nativefier-icons/';
|
|
|
|
type GitCloudIcon = {
|
|
ext?: string;
|
|
name?: string;
|
|
score?: number;
|
|
url?: string;
|
|
};
|
|
|
|
function getMaxMatchScore(iconWithScores: GitCloudIcon[]): number {
|
|
const score = iconWithScores.reduce((maxScore, currentIcon) => {
|
|
const currentScore = currentIcon.score;
|
|
if (currentScore && currentScore > maxScore) {
|
|
return currentScore;
|
|
}
|
|
return maxScore;
|
|
}, 0);
|
|
log.debug('Max icon match score:', score);
|
|
return score;
|
|
}
|
|
|
|
function getMatchingIcons(
|
|
iconsWithScores: GitCloudIcon[],
|
|
maxScore: number,
|
|
): GitCloudIcon[] {
|
|
return iconsWithScores.filter((item) => item.score === maxScore);
|
|
}
|
|
|
|
function mapIconWithMatchScore(
|
|
cloudIcons: { name: string; url: string }[],
|
|
targetUrl: string,
|
|
): GitCloudIcon[] {
|
|
const normalisedTargetUrl = targetUrl.toLowerCase();
|
|
return cloudIcons.map((item) => {
|
|
const itemWords = item.name.split(GITCLOUD_SPACE_DELIMITER);
|
|
const score: number = itemWords.reduce(
|
|
(currentScore: number, word: string) => {
|
|
if (normalisedTargetUrl.includes(word)) {
|
|
return currentScore + 1;
|
|
}
|
|
return currentScore;
|
|
},
|
|
0,
|
|
);
|
|
|
|
return { ...item, ext: path.extname(item.url), score };
|
|
});
|
|
}
|
|
|
|
async function inferIconFromStore(
|
|
targetUrl: string,
|
|
platform: string,
|
|
): Promise<DownloadResult | undefined> {
|
|
log.debug(`Inferring icon from store for ${targetUrl} on ${platform}`);
|
|
const allowedFormats = new Set<string | undefined>(
|
|
getAllowedIconFormats(platform),
|
|
);
|
|
|
|
const cloudIcons = await gitCloud(GITCLOUD_URL);
|
|
log.debug(`Got ${cloudIcons.length} icons from gitcloud`);
|
|
const iconWithScores = mapIconWithMatchScore(cloudIcons, targetUrl);
|
|
const maxScore = getMaxMatchScore(iconWithScores);
|
|
|
|
if (maxScore === 0) {
|
|
log.debug('No relevant icon in store.');
|
|
return undefined;
|
|
}
|
|
|
|
const iconsMatchingScore = getMatchingIcons(iconWithScores, maxScore);
|
|
const iconsMatchingExt = iconsMatchingScore.filter((icon) =>
|
|
allowedFormats.has(icon.ext ?? path.extname(icon.url as string)),
|
|
);
|
|
const matchingIcon = iconsMatchingExt[0];
|
|
const iconUrl = matchingIcon && matchingIcon.url;
|
|
|
|
if (!iconUrl) {
|
|
log.debug('Could not infer icon from store');
|
|
return undefined;
|
|
}
|
|
return downloadFile(iconUrl);
|
|
}
|
|
|
|
export async function inferIcon(
|
|
targetUrl: string,
|
|
platform: string,
|
|
): Promise<string | undefined> {
|
|
log.debug(`Inferring icon for ${targetUrl} on ${platform}`);
|
|
const tmpDirPath = getTempDir('iconinfer');
|
|
|
|
let icon: { ext: string; data: Buffer } | undefined =
|
|
await inferIconFromStore(targetUrl, platform);
|
|
if (!icon) {
|
|
const ext = platform === 'win32' ? '.ico' : '.png';
|
|
log.debug(`Trying to extract a ${ext} icon from the page.`);
|
|
icon = await pageIcon(targetUrl, { ext });
|
|
}
|
|
if (!icon) {
|
|
return undefined;
|
|
}
|
|
log.debug(`Got an icon from the page.`);
|
|
|
|
const iconPath = path.join(tmpDirPath, `/icon${icon.ext}`);
|
|
log.debug(
|
|
`Writing ${(icon.data.length / 1024).toFixed(1)} kb icon to ${iconPath}`,
|
|
);
|
|
await writeFileAsync(iconPath, icon.data);
|
|
return iconPath;
|
|
}
|