feat: add support i18n (#1468)

This commit is contained in:
JellyBrick
2023-12-01 01:30:46 +09:00
committed by GitHub
parent 7f71c36dc0
commit 7401cf69ad
65 changed files with 1226 additions and 303 deletions

View File

@ -5,6 +5,7 @@ import style from './style.css?inline';
import { createPlugin } from '@/utils';
import { onConfigChange, onMainLoad } from './main';
import { onPlayerApiReady, onRendererLoad } from './renderer';
import { t } from '@/i18n';
export type DownloaderPluginConfig = {
enabled: boolean;
@ -25,8 +26,8 @@ export const defaultConfig: DownloaderPluginConfig = {
};
export default createPlugin({
name: 'Downloader',
description: 'Downloads MP3 / source audio directly from the interface',
name: t('plugins.downloader.name'),
description: t('plugins.downloader.description'),
restartNeeded: true,
config: defaultConfig,
stylesheets: [style],

View File

@ -34,6 +34,8 @@ import { cleanupName, getImage, SongInfo } from '@/providers/song-info';
import { getNetFetchAsFetch } from '@/plugins/utils/main';
import { cache } from '@/providers/decorators';
import { t } from '@/i18n';
import { YoutubeFormatList, type Preset, DefaultPresetList } from '../types';
import type { DownloaderPluginConfig } from '../index';
@ -74,9 +76,9 @@ const sendError = (error: Error, source?: string) => {
console.trace(error);
dialog.showMessageBox(win, {
type: 'info',
buttons: ['OK'],
title: 'Error in download!',
message: 'Argh! Apologies, download failed…',
buttons: [t('plugins.downloader.backend.dialog.error.buttons.ok')],
title: t('plugins.downloader.backend.dialog.error.title'),
message: t('plugins.downloader.backend.dialog.error.message'),
detail: message,
});
};
@ -179,20 +181,27 @@ async function downloadSongUnsafe(
}
};
sendFeedback('Downloading...', 2);
sendFeedback(
t('plugins.downloader.backend.feedback.downloading'),
2,
);
let id: string | null;
if (isId) {
id = idOrUrl;
} else {
id = getVideoId(idOrUrl);
if (typeof id !== 'string') throw new Error('Video not found');
if (typeof id !== 'string') throw new Error(
t('plugins.downloader.backend.feedback.video-id-not-found'),
);
}
let info: TrackInfo | VideoInfo = await yt.music.getInfo(id);
if (!info) {
throw new Error('Video not found');
throw new Error(
t('plugins.downloader.backend.feedback.video-id-not-found'),
);
}
const metadata = getMetadata(info);
@ -277,7 +286,11 @@ async function downloadSongUnsafe(
const stream = await info.download(downloadOptions);
console.info(
`Downloading ${metadata.artist} - ${metadata.title} [${metadata.videoId}]`,
t('plugins.downloader.backend.feedback.download-info', {
artist: metadata.artist,
title: metadata.title,
videoId: metadata.videoId,
}),
);
const iterableStream = Utils.streamToIterable(stream);
@ -312,7 +325,9 @@ async function downloadSongUnsafe(
}
sendFeedback(null, -1);
console.info(`Done: "${filePath}"`);
console.info(t('plugins.downloader.backend.feedback.done', {
filePath,
}));
}
async function iterableStreamToTargetFile(
@ -331,13 +346,21 @@ async function iterableStreamToTargetFile(
chunks.push(chunk);
const ratio = downloaded / contentLength;
const progress = Math.floor(ratio * 100);
sendFeedback(`Download: ${progress}%`, ratio);
sendFeedback(
t('plugins.downloader.backend.feedback.downloading-progress', {
percent: progress,
}),
ratio,
);
// 15% for download, 85% for conversion
// This is a very rough estimate, trying to make the progress bar look nice
increasePlaylistProgress(ratio * 0.15);
}
sendFeedback('Loading…', 2); // Indefinite progress bar after download
sendFeedback(
t('plugins.downloader.backend.feedback.loading'),
2,
); // Indefinite progress bar after download
const buffer = Buffer.concat(chunks);
const safeVideoName = randomBytes(32).toString('hex');
@ -348,13 +371,18 @@ async function iterableStreamToTargetFile(
await ffmpeg.load();
}
sendFeedback('Preparing file');
sendFeedback(t('plugins.downloader.backend.feedback.preparing-file'));
ffmpeg.FS('writeFile', safeVideoName, buffer);
sendFeedback('Converting');
sendFeedback(t('plugins.downloader.backend.feedback.converting'));
ffmpeg.setProgress(({ ratio }) => {
sendFeedback(`Converting: ${Math.floor(ratio * 100)}%`, ratio);
sendFeedback(
t('plugins.downloader.backend.feedback.conversion-progress', {
percent: Math.floor(ratio * 100),
}),
ratio,
);
increasePlaylistProgress(0.15 + (ratio * 0.85));
});
@ -371,7 +399,9 @@ async function iterableStreamToTargetFile(
ffmpeg.FS('unlink', safeVideoName);
}
sendFeedback('Saving…');
sendFeedback(
t('plugins.downloader.backend.feedback.saving'),
);
try {
return ffmpeg.FS('readFile', safeVideoNameWithExtension);
@ -397,7 +427,9 @@ async function writeID3(
sendFeedback: (str: string, value?: number) => void,
) {
try {
sendFeedback('Writing ID3 tags...');
sendFeedback(
t('plugins.downloader.backend.feedback.writing-id3'),
);
const tags: NodeID3.Tags = {};
// Create the metadata tags
@ -452,14 +484,22 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
getPlaylistID(givenUrl) || getPlaylistID(new URL(playingUrl));
if (!playlistId) {
sendError(new Error('No playlist ID found'));
sendError(new Error(
t('plugins.downloader.backend.feedback.playlist-id-not-found'),
));
return;
}
const sendFeedback = (message?: unknown) => sendFeedback_(win, message);
console.log(`trying to get playlist ID: '${playlistId}'`);
sendFeedback('Getting playlist info…');
console.log(
t('plugins.downloader.backend.feedback.trying-to-get-playlist-id', {
playlistId,
}),
);
sendFeedback(
t('plugins.downloader.backend.feedback.getting-playlist-info'),
);
let playlist: Playlist;
const items: YTNodes.MusicResponsiveListItem[] = [];
try {
@ -470,16 +510,18 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
} catch (error: unknown) {
sendError(
Error(
`Error getting playlist info: make sure it isn't a private or "Mixed for you" playlist\n\n${String(
error,
)}`,
t('plugins.downloader.backend.feedback.playlist-is-mix-or-private', {
error: String(error),
}),
),
);
return;
}
if (!playlist || !playlist.items || playlist.items.length === 0) {
sendError(new Error('Playlist is empty'));
sendError(new Error(
t('plugins.downloader.backend.feedback.playlist-is-empty'),
));
}
const normalPlaylistTitle = playlist.header?.title?.text;
@ -500,7 +542,9 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
}
if (items.length === 1) {
sendFeedback('Playlist has only one item, downloading it directly');
sendFeedback(
t('plugins.downloader.backend.feedback.playlist-has-only-one-song'),
);
await downloadSongFromId(items.at(0)!.id!);
return;
}
@ -514,7 +558,11 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
const playlistFolder = join(folder, safePlaylistTitle);
if (existsSync(playlistFolder)) {
if (!config.skipExisting) {
sendError(new Error(`The folder ${playlistFolder} already exists`));
sendError(new Error(
t('plugins.downloader.backend.feedback.folder-already-exists', {
playlistFolder,
})
));
return;
}
} else {
@ -523,15 +571,23 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
dialog.showMessageBox(win, {
type: 'info',
buttons: ['OK'],
title: 'Started Download',
message: `Downloading Playlist "${playlistTitle}"`,
detail: `(${items.length} songs)`,
buttons: [t('plugins.downloader.backend.dialog.start-download-playlist.buttons.ok')],
title: t('plugins.downloader.backend.dialog.start-download-playlist.title'),
message: t('plugins.downloader.backend.dialog.start-download-playlist.message', {
playlistTitle,
}),
detail: t('plugins.downloader.backend.dialog.start-download-playlist.detail', {
playlistSize: items.length,
}),
});
if (is.dev()) {
console.log(
`Downloading playlist "${playlistTitle}" - ${items.length} songs (${playlistId})`,
t('plugins.downloader.backend.feedback.downloading-playlist', {
playlistTitle,
playlistSize: items.length,
playlistId,
}),
);
}
@ -551,7 +607,12 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
try {
for (const song of items) {
sendFeedback(`Downloading ${counter}/${items.length}...`);
sendFeedback(
t('plugins.downloader.backend.feedback.downloading-counter', {
current: counter,
total: items.length,
})
);
const trackId = isAlbum ? counter : undefined;
await downloadSongFromId(
song.id!,
@ -561,9 +622,11 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
).catch((error) =>
sendError(
new Error(
`Error downloading "${
song.author!.name
} - ${song.title!}":\n ${error}`,
t('plugins.downloader.backend.feedback.error-while-downloading', {
author: song.author!.name,
title: song.title!,
error: String(error),
}),
),
),
);

View File

@ -8,6 +8,7 @@ import type { MenuContext } from '@/types/contexts';
import type { MenuTemplate } from '@/menu';
import type { DownloaderPluginConfig } from './index';
import { t } from '@/i18n';
export const onMenu = async ({
getConfig,
@ -21,7 +22,7 @@ export const onMenu = async ({
click: () => downloadPlaylist(),
},
{
label: 'Choose download folder',
label: t('plugins.downloader.menu.choose-download-folder'),
click() {
const result = dialog.showOpenDialogSync({
properties: ['openDirectory', 'createDirectory'],
@ -33,7 +34,7 @@ export const onMenu = async ({
},
},
{
label: 'Presets',
label: t('plugins.downloader.menu.presets'),
submenu: Object.keys(DefaultPresetList).map((preset) => ({
label: preset,
type: 'radio',
@ -44,7 +45,7 @@ export const onMenu = async ({
})),
},
{
label: 'Skip existing files',
label: t('plugins.downloader.menu.skip-existing'),
type: 'checkbox',
checked: config.skipExisting,
click(item) {

View File

@ -4,11 +4,14 @@ import defaultConfig from '@/config/defaults';
import { getSongMenu } from '@/providers/dom-elements';
import { getSongInfo } from '@/providers/song-info-front';
import { LoggerPrefix } from '@/utils';
import { ElementFromHtml } from '../utils/renderer';
import type { RendererContext } from '@/types/contexts';
import type { DownloaderPluginConfig } from './index';
import { t } from '@/i18n';
let menu: Element | null = null;
let progress: Element | null = null;
@ -75,7 +78,10 @@ export const onRendererLoad = ({
if (progress) {
progress.innerHTML = feedback || 'Download';
} else {
console.warn('Cannot update progress');
console.warn(
LoggerPrefix,
t('plugins.downloader.renderer.can-not-update-progress'),
);
}
});
};

View File

@ -39,7 +39,7 @@
class="text style-scope ytmusic-menu-navigation-item-renderer"
id="ytmcustom-download"
>
Download
<ytmd-trans key="plugins.downloader.templates.button"></ytmd-trans>
</div>
</a>
</div>