【其他】MGG转MP3
AI-摘要
GPT
AI初始化中...
介绍自己
生成本文简介
推荐相关文章
前往主页
前往tianli博客
最近碰到一个问题就是我个需要让我给他往u盘里下载歌曲,歌曲格式是mp3的,第一时间我想到的就是用qq音乐下载因为我有会员直接下载就可以,但是最后我去看下载好的音乐的时候缺发现是mgg格式。经过一番搜索发现mgg格式是qq音乐专用的,所以未了解决这个问题
1.软件准备
QQ音乐(版本不高于19.51)自用19.43
https://cloud.xiaoshuai.online/s/jRfM gthu格式工厂(转换ogg到mp3)
http://formatfactory.org/CN/download.html MusicTag(补全音乐歌词封面等信息)
https://cloud.xiaoshuai.online/s/k5h6 mkop
2.查看QQ音乐版本
首先保证QQ音乐版本不高于19.51,若高于,需要重新安装不高于19.51的版本,下面提供两种该版本下载方法:(!!最新版本的QQ音乐虽然也能下载.mgg文件,但转换工具转成的.ogg文件将会无法播放,并且.ogg文件通过格式工厂再行转换会失败,本人亲测19.43版本下完全可用)
目前 Windows 客户端 19.51 或更低版本下载的歌曲文件无需密钥,其余平台的官方正式版本均需要提取密钥。对于高版本的只有获取了这个密钥才能去解析这个mgg格式。所以需要降级.
降级安装包可以从这个网站获取
3.从QQ音乐下载歌曲
4.安装脚本猫(如果只需要一首歌不用安装)
因为音乐解锁网站不能批量下载,所以我写了个针对音乐解锁网站的批量下载工具
// ==UserScript==
// @name 音乐解锁助手
// @namespace ScriptCat
// @version 0.1.0
// @description 解锁音乐工具增强脚本
// @author You
// @match https://tool.liumingye.cn/unlock-music/
// @grant GM_notification
// @license MIT
// @homepage https://scriptcat.org/
// ==/UserScript==
(function() {
'use strict';
// 初始化日志函数
const log = (...args) => {
console.log('[音乐解锁助手]', ...args);
};
// 创建下载按钮界面
function createBatchUI() {
const container = document.createElement('div');
container.style.cssText = `
position: fixed;
top: 10px;
left: 10px;
background: var(--chakra-colors-white);
padding: 15px;
border-radius: var(--chakra-radii-lg);
box-shadow: var(--chakra-shadows-lg);
z-index: 10000;
width: 320px;
user-select: none;
font-family: var(--chakra-fonts-body);
`;
// 添加拖动功能
let isDragging = false;
let currentX = 10; // 初始X位置
let currentY = 10; // 初始Y位置
let initialX;
let initialY;
function dragStart(e) {
if (e.type === "mousedown") {
initialX = e.clientX - currentX;
initialY = e.clientY - currentY;
} else {
initialX = e.touches[0].clientX - currentX;
initialY = e.touches[0].clientY - currentY;
}
if (e.target === titleBar) {
isDragging = true;
}
}
function dragEnd() {
isDragging = false;
}
function drag(e) {
if (isDragging) {
e.preventDefault();
if (e.type === "mousemove") {
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
} else {
currentX = e.touches[0].clientX - initialX;
currentY = e.touches[0].clientY - initialY;
}
// 确保不会拖出屏幕
const rect = container.getBoundingClientRect();
const maxX = window.innerWidth - rect.width;
const maxY = window.innerHeight - rect.height;
currentX = Math.min(Math.max(0, currentX), maxX);
currentY = Math.min(Math.max(0, currentY), maxY);
container.style.transform = `translate(${currentX}px, ${currentY}px)`;
}
}
// 标题栏
const titleBar = document.createElement('div');
titleBar.textContent = '批量下载助手';
titleBar.style.cssText = `
margin: -15px -15px 15px -15px;
padding: 12px 15px;
background: var(--chakra-colors-blue-500);
color: white;
border-radius: var(--chakra-radii-lg) var(--chakra-radii-lg) 0 0;
font-weight: var(--chakra-fontWeights-bold);
font-size: 16px;
cursor: move;
text-align: center;
`;
// 添加拖动事件监听
titleBar.addEventListener('mousedown', dragStart);
titleBar.addEventListener('touchstart', dragStart);
document.addEventListener('mousemove', drag);
document.addEventListener('touchmove', drag);
document.addEventListener('mouseup', dragEnd);
document.addEventListener('touchend', dragEnd);
// 序号设置卡片
const numberCard = document.createElement('div');
numberCard.style.cssText = `
background: var(--chakra-colors-white);
border: 1px solid var(--chakra-colors-gray-200);
border-radius: var(--chakra-radii-md);
padding: 15px;
margin-bottom: 12px;
`;
const numberTitle = document.createElement('div');
numberTitle.textContent = '序号设置';
numberTitle.style.cssText = `
font-weight: 600;
margin-bottom: 12px;
color: var(--chakra-colors-gray-700);
display: flex;
align-items: center;
`;
// 添加复选框到标题旁边
const checkboxWrapper = document.createElement('div');
checkboxWrapper.style.cssText = `
display: flex;
align-items: center;
margin-left: auto;
`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = 'addPrefix';
checkbox.style.marginRight = '4px';
const checkboxLabel = document.createElement('label');
checkboxLabel.htmlFor = 'addPrefix';
checkboxLabel.textContent = '启用';
checkboxLabel.style.fontSize = '14px';
checkboxWrapper.appendChild(checkbox);
checkboxWrapper.appendChild(checkboxLabel);
numberTitle.appendChild(checkboxWrapper);
// 输入区域使用网格布局
const inputGrid = document.createElement('div');
inputGrid.style.cssText = `
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
`;
// 创建所有输入框
const digitInput = document.createElement('input');
digitInput.type = 'number';
digitInput.value = '2';
digitInput.min = '1';
digitInput.max = '10';
digitInput.title = '序号位数';
digitInput.style.cssText = `
padding: 4px 8px;
border: 1px solid var(--chakra-colors-gray-200);
border-radius: var(--chakra-radii-md);
text-align: center;
width: 100%;
`;
const startNumInput = document.createElement('input');
startNumInput.type = 'number';
startNumInput.value = '1';
startNumInput.min = '0';
startNumInput.title = '起始序号';
startNumInput.style.cssText = digitInput.style.cssText;
const separatorInput = document.createElement('input');
separatorInput.type = 'text';
separatorInput.value = '_';
separatorInput.title = '分隔符';
separatorInput.style.cssText = digitInput.style.cssText;
const prefixInput = document.createElement('input');
prefixInput.type = 'text';
prefixInput.placeholder = '自定义前缀(可选)';
prefixInput.style.cssText = digitInput.style.cssText;
// 预览卡片
const previewCard = document.createElement('div');
previewCard.style.cssText = `
background: var(--chakra-colors-gray-50);
border-radius: var(--chakra-radii-md);
padding: 12px;
margin-bottom: 12px;
font-size: 13px;
color: var(--chakra-colors-gray-600);
word-break: break-all;
`;
previewCard.textContent = 'example.mp3';
// 添加位置选择
const positionSelect = document.createElement('select');
positionSelect.style.cssText = `
padding: 4px 8px;
border: 1px solid var(--chakra-colors-gray-200);
border-radius: var(--chakra-radii-md);
background: white;
width: 100%;
`;
// 添加位置选项
const positions = [
{ value: 'before', text: '在名称前' },
{ value: 'after', text: '在名称后' },
{ value: 'custom', text: '指定位置' }
];
positions.forEach(pos => {
const option = document.createElement('option');
option.value = pos.value;
option.textContent = pos.text;
positionSelect.appendChild(option);
});
// 添加位置输入框
const positionInput = document.createElement('input');
positionInput.type = 'number';
positionInput.min = '0';
positionInput.value = '0';
positionInput.title = '指定插入位置';
positionInput.style.cssText = `
padding: 4px 8px;
border: 1px solid var(--chakra-colors-gray-200);
border-radius: var(--chakra-radii-md);
text-align: center;
width: 60px;
display: none; // 默认隐藏
`;
// 监听位置选择变化
positionSelect.addEventListener('change', () => {
positionInput.style.display = positionSelect.value === 'custom' ? 'block' : 'none';
updatePreview();
});
// 更新预览函数
function updatePreview() {
if (!checkbox.checked) {
previewCard.textContent = 'example.mp3';
return;
}
const prefix = prefixInput.value.trim();
const separator = separatorInput.value || '_';
const paddedIndex = String(parseInt(startNumInput.value) || 1).padStart(parseInt(digitInput.value) || 2, '0');
const position = positionSelect.value;
const customPosition = parseInt(positionInput.value) || 0;
let newName;
const fileName = 'example';
const ext = '.mp3';
switch (position) {
case 'before':
newName = prefix
? `${prefix}${separator}${paddedIndex}${separator}${fileName}${ext}`
: `${paddedIndex}${separator}${fileName}${ext}`;
break;
case 'after':
newName = prefix
? `${paddedIndex}${separator}${fileName}${separator}${prefix}${ext}`
: `${paddedIndex}${separator}${fileName}${ext}`;
break;
case 'custom':
if (prefix) {
const beforePos = fileName.slice(0, customPosition);
const afterPos = fileName.slice(customPosition);
newName = `${paddedIndex}${separator}${beforePos}${separator}${prefix}${separator}${afterPos}${ext}`;
} else {
newName = `${paddedIndex}${separator}${fileName}${ext}`;
}
break;
}
previewCard.textContent = newName;
}
// 为所有输入添加事件监听
[checkbox, digitInput, startNumInput, separatorInput, prefixInput].forEach(input => {
input.addEventListener('input', updatePreview);
});
// 创建输入组
function createInputGroup(label, input) {
const group = document.createElement('div');
group.style.cssText = `
display: flex;
flex-direction: column;
gap: 4px;
`;
const labelEl = document.createElement('div');
labelEl.textContent = label;
labelEl.style.cssText = `
font-size: 12px;
color: var(--chakra-colors-gray-600);
`;
group.appendChild(labelEl);
group.appendChild(input);
return group;
}
// 前缀设置卡片
const prefixCard = document.createElement('div');
prefixCard.style.cssText = numberCard.style.cssText;
const prefixTitle = document.createElement('div');
prefixTitle.textContent = '自定义文字设置';
prefixTitle.style.cssText = numberTitle.style.cssText;
const prefixContent = document.createElement('div');
prefixContent.style.cssText = `
display: flex;
flex-direction: column;
gap: 12px;
`;
// 添加位置选项
const positionWrapper = document.createElement('div');
positionWrapper.style.cssText = `
display: flex;
gap: 8px;
align-items: flex-end;
`;
positionWrapper.appendChild(createInputGroup('添加位置', positionSelect));
positionWrapper.appendChild(positionInput);
prefixContent.appendChild(positionWrapper);
// 分隔符和自定义文字的容器
const customTextWrapper = document.createElement('div');
customTextWrapper.style.cssText = `
display: grid;
grid-template-columns: 60px 1fr;
gap: 12px;
align-items: start;
`;
// 修改分隔符输入框
separatorInput.maxLength = 1; // 限制只能输入一个字符
separatorInput.style.textAlign = 'center';
// 修改自定义文字输入框
prefixInput.placeholder = '自定义文字';
// 组装UI
numberCard.appendChild(numberTitle);
numberCard.appendChild(inputGrid);
inputGrid.appendChild(createInputGroup('位数', digitInput));
inputGrid.appendChild(createInputGroup('起始值', startNumInput));
customTextWrapper.appendChild(createInputGroup('分隔符', separatorInput));
customTextWrapper.appendChild(createInputGroup('自定义文字', prefixInput));
prefixContent.appendChild(customTextWrapper);
prefixCard.appendChild(prefixTitle);
prefixCard.appendChild(prefixContent);
// 下载按钮
const downloadButton = document.createElement('button');
downloadButton.textContent = '开始批量下载';
downloadButton.style.cssText = `
width: 100%;
padding: 10px;
background: var(--chakra-colors-blue-500);
color: white;
border: none;
border-radius: var(--chakra-radii-md);
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
margin-top: 15px;
&:hover {
background: var(--chakra-colors-blue-600);
}
`;
// 状态显示
const status = document.createElement('div');
status.style.cssText = `
margin-top: 10px;
font-size: 13px;
color: var(--chakra-colors-gray-600);
text-align: center;
`;
// 组装UI
container.appendChild(titleBar);
container.appendChild(numberCard);
container.appendChild(prefixCard);
container.appendChild(previewCard);
container.appendChild(downloadButton);
container.appendChild(status);
// 添加到body并设置初始位置
document.body.appendChild(container);
container.style.transform = `translate(${currentX}px, ${currentY}px)`;
// 添加位置输入框的事件监听
positionInput.addEventListener('input', updatePreview);
// 添加计数显示到状态栏
function updateMusicCount() {
// 查找所有音频元素
const musicItems = document.querySelectorAll('audio');
// 查找所有已下载的项(通过下载按钮的状态来判断)
const downloadedItems = document.querySelectorAll('a.chakra-link[style*="opacity: 0.5"]');
status.textContent = `共 ${musicItems.length} 个文件,已下载 ${downloadedItems.length} 个`;
}
// 修改下载按钮点击事件
downloadButton.addEventListener('click', async () => {
const downloadLinks = Array.from(document.querySelectorAll('a.chakra-link')).filter(link =>
link.hasAttribute('download')
);
if (downloadLinks.length === 0) {
status.textContent = '没有找到可下载的文件!';
return;
}
status.textContent = `开始下载 ${downloadLinks.length} 个文件...`;
downloadButton.disabled = true;
try {
let count = 0;
const addPrefix = checkbox.checked;
const prefix = prefixInput.value.trim();
const digits = parseInt(digitInput.value) || 2;
const separator = separatorInput.value || '_';
const startNum = parseInt(startNumInput.value) || 1;
const position = positionSelect.value;
for (const link of downloadLinks) {
// 获取音乐项的容器元素
const musicItem = link.closest('.chakra-collapse');
// 处理文件名
if (addPrefix) {
const originalName = link.getAttribute('download');
const paddedIndex = String(startNum + count).padStart(digits, '0');
// 根据选择的位置生成新文件名
let newName;
const nameWithoutExt = originalName.replace(/\.[^/.]+$/, '');
const ext = originalName.match(/\.[^/.]+$/)?.[0] || '';
switch (position) {
case 'before':
newName = prefix
? `${prefix}${separator}${paddedIndex}${separator}${originalName}`
: `${paddedIndex}${separator}${originalName}`;
break;
case 'after':
newName = prefix
? `${paddedIndex}${separator}${nameWithoutExt}${separator}${prefix}${ext}`
: `${paddedIndex}${separator}${originalName}`;
break;
case 'custom':
// 可以添加更复杂的自定义位置逻辑
newName = prefix
? `${paddedIndex}${separator}${nameWithoutExt}${separator}${prefix}${ext}`
: `${paddedIndex}${separator}${originalName}`;
break;
}
link.setAttribute('download', newName);
}
// 确保链接在视图中
link.scrollIntoView({ behavior: 'smooth', block: 'center' });
// 触发下载
link.click();
// 标记已下载的音乐项
if (musicItem) {
musicItem.style.cssText += `
border: 2px solid #ff4444 !important;
border-radius: 8px;
margin: 5px 0;
padding: 5px;
transform: scale(0.95);
transform-origin: center;
transition: transform 0.3s ease;
opacity: 0.8;
`;
// 同时标记下载按钮
link.style.opacity = '0.5';
}
count++;
updateMusicCount();
await new Promise(resolve => setTimeout(resolve, 800));
}
status.textContent = `下载完成!共 ${downloadLinks.length} 个文件`;
GM_notification({
text: `已下载 ${count} 个文件`,
title: '批量下载完成',
timeout: 3000
});
} catch (err) {
status.textContent = '下载过程出错:' + err.message;
console.error(err);
} finally {
downloadButton.disabled = false;
updateMusicCount(); // 最后更新一次计数
}
});
// 初始化时显示计数
updateMusicCount();
// 添加 MutationObserver 监听音乐列表变化
const observer = new MutationObserver(() => {
updateMusicCount();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// 返回container
return container;
}
// 脚本初始化
function init() {
log('脚本已启动');
function checkAndCreateUI() {
// 检查特定元素是否存在,表明页面已完全加载
const mainContent = document.querySelector('.chakra-ui-light');
if (mainContent) {
// 确保UI只创建一次
if (!document.querySelector('#batch-download-helper')) {
const container = createBatchUI();
container.id = 'batch-download-helper';
log('批量下载界面已添加');
}
} else {
setTimeout(checkAndCreateUI, 500); // 减少等待时间
}
}
// 开始检查
checkAndCreateUI();
// 监听路由变化(因为是SPA)
const observer = new MutationObserver(() => {
checkAndCreateUI();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// 确保在页面准备好后执行
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
5.将mgg文件解锁为ogg文件
然后手动下载或者批量下载
6.使用格式工厂将ogg文件转为mp3文件
7.使用MusicTag补全音乐信息
文件-添加目录
刷新下,要是没有出现歌曲可以试一下
全选所有文件
批量-自动匹配标签
选择需要补全的信息单击确定完成
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果