mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-29 11:27:23 +08:00
Merge pull request #464 from souvenp/feat/flac-tags
feat: flac tags support and optimize cover images
This commit is contained in:
@@ -32,12 +32,14 @@
|
|||||||
"electron-window-state": "^5.0.3",
|
"electron-window-state": "^5.0.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"file-type": "^21.0.0",
|
"file-type": "^21.0.0",
|
||||||
|
"flac-tagger": "^1.0.7",
|
||||||
"font-list": "^1.5.1",
|
"font-list": "^1.5.1",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"music-metadata": "^11.2.3",
|
"music-metadata": "^11.2.3",
|
||||||
"netease-cloud-music-api-alger": "^4.26.1",
|
"netease-cloud-music-api-alger": "^4.26.1",
|
||||||
"node-id3": "^0.2.9",
|
"node-id3": "^0.2.9",
|
||||||
"node-machine-id": "^1.1.12",
|
"node-machine-id": "^1.1.12",
|
||||||
|
"sharp": "^0.34.3",
|
||||||
"vue-i18n": "^11.1.3"
|
"vue-i18n": "^11.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import * as mm from 'music-metadata';
|
|||||||
import * as NodeID3 from 'node-id3';
|
import * as NodeID3 from 'node-id3';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { FlacTagMap, writeFlacTags } from 'flac-tagger';
|
||||||
|
import sharp from 'sharp';
|
||||||
import { getStore } from './config';
|
import { getStore } from './config';
|
||||||
|
|
||||||
const MAX_CONCURRENT_DOWNLOADS = 3;
|
const MAX_CONCURRENT_DOWNLOADS = 3;
|
||||||
@@ -386,7 +387,7 @@ async function downloadMusic(
|
|||||||
let formattedFilename = filename;
|
let formattedFilename = filename;
|
||||||
if (songInfo) {
|
if (songInfo) {
|
||||||
// 准备替换变量
|
// 准备替换变量
|
||||||
const artistName = songInfo.ar?.map((a: any) => a.name).join('/') || '未知艺术家';
|
const artistName = songInfo.ar?.map((a: any) => a.name).join('、') || '未知艺术家';
|
||||||
const songName = songInfo.name || filename;
|
const songName = songInfo.name || filename;
|
||||||
const albumName = songInfo.al?.name || '未知专辑';
|
const albumName = songInfo.al?.name || '未知专辑';
|
||||||
|
|
||||||
@@ -576,8 +577,39 @@ async function downloadMusic(
|
|||||||
timeout: 10000
|
timeout: 10000
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取封面图片的buffer
|
const originalCoverBuffer = Buffer.from(coverResponse.data);
|
||||||
coverImageBuffer = Buffer.from(coverResponse.data);
|
const TWO_MB = 2 * 1024 * 1024;
|
||||||
|
// 检查图片大小是否超过2MB
|
||||||
|
if (originalCoverBuffer.length > TWO_MB) {
|
||||||
|
const originalSizeMB = (originalCoverBuffer.length / (1024 * 1024)).toFixed(2);
|
||||||
|
console.log(`封面图大于2MB (${originalSizeMB} MB),开始压缩...`);
|
||||||
|
try {
|
||||||
|
// 使用 sharp 进行压缩
|
||||||
|
coverImageBuffer = await sharp(originalCoverBuffer)
|
||||||
|
.resize({
|
||||||
|
width: 1600,
|
||||||
|
height: 1600,
|
||||||
|
fit: 'inside',
|
||||||
|
withoutEnlargement: true
|
||||||
|
})
|
||||||
|
.jpeg({
|
||||||
|
quality: 80,
|
||||||
|
mozjpeg: true
|
||||||
|
})
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const compressedSizeMB = (coverImageBuffer.length / (1024 * 1024)).toFixed(2);
|
||||||
|
console.log(`封面图压缩完成,新大小: ${compressedSizeMB} MB`);
|
||||||
|
|
||||||
|
} catch (compressionError) {
|
||||||
|
console.error('封面图压缩失败,将使用原图:', compressionError);
|
||||||
|
coverImageBuffer = originalCoverBuffer; // 如果压缩失败,则回退使用原始图片
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果图片不大于2MB,直接使用原图
|
||||||
|
coverImageBuffer = originalCoverBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('封面已准备好,将写入元数据');
|
console.log('封面已准备好,将写入元数据');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,7 +620,7 @@ async function downloadMusic(
|
|||||||
|
|
||||||
const fileFormat = fileExtension.toLowerCase();
|
const fileFormat = fileExtension.toLowerCase();
|
||||||
const artistNames =
|
const artistNames =
|
||||||
(songInfo?.ar || songInfo?.song?.artists)?.map((a: any) => a.name).join('/ ') || '未知艺术家';
|
(songInfo?.ar || songInfo?.song?.artists)?.map((a: any) => a.name).join('、') || '未知艺术家';
|
||||||
|
|
||||||
// 根据文件类型处理元数据
|
// 根据文件类型处理元数据
|
||||||
if (['.mp3'].includes(fileFormat)) {
|
if (['.mp3'].includes(fileFormat)) {
|
||||||
@@ -598,7 +630,7 @@ async function downloadMusic(
|
|||||||
NodeID3.removeTags(finalFilePath);
|
NodeID3.removeTags(finalFilePath);
|
||||||
|
|
||||||
const tags = {
|
const tags = {
|
||||||
title: filename,
|
title: songInfo?.name,
|
||||||
artist: artistNames,
|
artist: artistNames,
|
||||||
TPE1: artistNames,
|
TPE1: artistNames,
|
||||||
TPE2: artistNames,
|
TPE2: artistNames,
|
||||||
@@ -634,10 +666,35 @@ async function downloadMusic(
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error writing ID3 tags:', err);
|
console.error('Error writing ID3 tags:', err);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (['.flac'].includes(fileFormat)) {
|
||||||
// 对于非MP3文件,使用music-metadata来写入元数据可能需要专门的库
|
try {
|
||||||
// 或者根据不同文件类型使用专用工具,暂时只记录但不处理
|
const tagMap: FlacTagMap = {
|
||||||
console.log(`文件类型 ${fileFormat} 不支持使用NodeID3写入标签,跳过元数据写入`);
|
TITLE: songInfo?.name,
|
||||||
|
ARTIST: artistNames,
|
||||||
|
ALBUM: songInfo?.al?.name || songInfo?.song?.album?.name || songInfo?.name || filename,
|
||||||
|
LYRICS: lyricsContent || '',
|
||||||
|
TRACKNUMBER: songInfo?.no ? String(songInfo.no) : undefined,
|
||||||
|
DATE: songInfo?.publishTime
|
||||||
|
? new Date(songInfo.publishTime).getFullYear().toString()
|
||||||
|
: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
await writeFlacTags(
|
||||||
|
{
|
||||||
|
tagMap,
|
||||||
|
picture: coverImageBuffer
|
||||||
|
? {
|
||||||
|
buffer: coverImageBuffer,
|
||||||
|
mime: 'image/jpeg'
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
finalFilePath
|
||||||
|
);
|
||||||
|
console.log('FLAC tags written successfully');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error writing FLAC tags:', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存下载信息
|
// 保存下载信息
|
||||||
@@ -683,7 +740,7 @@ async function downloadMusic(
|
|||||||
// 发送桌面通知
|
// 发送桌面通知
|
||||||
try {
|
try {
|
||||||
const artistNames =
|
const artistNames =
|
||||||
(songInfo?.ar || songInfo?.song?.artists)?.map((a: any) => a.name).join('/') ||
|
(songInfo?.ar || songInfo?.song?.artists)?.map((a: any) => a.name).join('、') ||
|
||||||
'未知艺术家';
|
'未知艺术家';
|
||||||
const notification = new Notification({
|
const notification = new Notification({
|
||||||
title: '下载完成',
|
title: '下载完成',
|
||||||
|
|||||||
Reference in New Issue
Block a user