mirror of
				https://git.unlock-music.dev/um/web.git
				synced 2025-11-04 22:03:29 +08:00 
			
		
		
		
	Add Experimental Support For Mgg
This commit is contained in:
		
							parent
							
								
									4e1bfb0b55
								
							
						
					
					
						commit
						2fc9368a92
					
				@ -75,7 +75,7 @@
 | 
				
			|||||||
                this.$notify.info({
 | 
					                this.$notify.info({
 | 
				
			||||||
                    title: '离线使用',
 | 
					                    title: '离线使用',
 | 
				
			||||||
                    message: '我们使用PWA技术,无网络也能使用<br/>' +
 | 
					                    message: '我们使用PWA技术,无网络也能使用<br/>' +
 | 
				
			||||||
                        '最近更新:支持bkcmp3/bkcflac/tkm<br/>' +
 | 
					                        '最近更新:提供实验性mgg支持<br/>' +
 | 
				
			||||||
                        '点击查看 <a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>',
 | 
					                        '点击查看 <a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>',
 | 
				
			||||||
                    dangerouslyUseHTMLString: true,
 | 
					                    dangerouslyUseHTMLString: true,
 | 
				
			||||||
                    duration: 10000,
 | 
					                    duration: 10000,
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ const NcmDecrypt = require("./ncm");
 | 
				
			|||||||
const QmcDecrypt = require("./qmc");
 | 
					const QmcDecrypt = require("./qmc");
 | 
				
			||||||
const RawDecrypt = require("./raw");
 | 
					const RawDecrypt = require("./raw");
 | 
				
			||||||
const MFlacDecrypt = require("./mflac");
 | 
					const MFlacDecrypt = require("./mflac");
 | 
				
			||||||
 | 
					const MggDecrypt = require("./mgg");
 | 
				
			||||||
const TmDecrypt = require("./tm");
 | 
					const TmDecrypt = require("./tm");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,6 +36,9 @@ export async function CommonDecrypt(file) {
 | 
				
			|||||||
        case "mflac"://QQ Music Desktop Flac
 | 
					        case "mflac"://QQ Music Desktop Flac
 | 
				
			||||||
            rt_data = await MFlacDecrypt.Decrypt(file.raw, raw_filename, raw_ext);
 | 
					            rt_data = await MFlacDecrypt.Decrypt(file.raw, raw_filename, raw_ext);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case "mgg":
 | 
				
			||||||
 | 
					            rt_data = await MggDecrypt.Decrypt(file.raw, raw_filename, raw_ext);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        case "tm2":// QQ Music IOS M4a
 | 
					        case "tm2":// QQ Music IOS M4a
 | 
				
			||||||
        case "tm6":// QQ Music IOS M4a
 | 
					        case "tm6":// QQ Music IOS M4a
 | 
				
			||||||
            rt_data = await TmDecrypt.Decrypt(file.raw, raw_filename);
 | 
					            rt_data = await TmDecrypt.Decrypt(file.raw, raw_filename);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										84
									
								
								src/decrypt/mgg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/decrypt/mgg.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					const musicMetadata = require("music-metadata-browser");
 | 
				
			||||||
 | 
					const util = require("./util");
 | 
				
			||||||
 | 
					export {Decrypt}
 | 
				
			||||||
 | 
					const FLAC_HEADER = [0x4F, 0x67, 0x67, 0x53, 0x00];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function Decrypt(file, raw_filename, raw_ext) {
 | 
				
			||||||
 | 
					    // 获取扩展名
 | 
				
			||||||
 | 
					    if (raw_ext !== "mgg") return {
 | 
				
			||||||
 | 
					        status: false,
 | 
				
			||||||
 | 
					        message: "File type is incorrect!",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    // 读取文件
 | 
				
			||||||
 | 
					    const fileBuffer = await util.GetArrayBuffer(file);
 | 
				
			||||||
 | 
					    const audioData = new Uint8Array(fileBuffer.slice(0, -0x170));
 | 
				
			||||||
 | 
					    const audioDataLen = audioData.length;
 | 
				
			||||||
 | 
					    const keyData = new Uint8Array(fileBuffer.slice(-0x170));
 | 
				
			||||||
 | 
					    const headData = new Uint8Array(fileBuffer.slice(0, 170));
 | 
				
			||||||
 | 
					    let seed;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        let resp = await queryKeyInfo(keyData, headData, raw_filename);
 | 
				
			||||||
 | 
					        let data = await resp.json();
 | 
				
			||||||
 | 
					        seed = new Mask(data.Mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            status: false,
 | 
				
			||||||
 | 
					            message: "此音乐无法解锁,目前mgg格式仅提供试验性支持",
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let cur = 0; cur < audioDataLen; ++cur) {
 | 
				
			||||||
 | 
					        audioData[cur] ^= seed.NextMask();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 导出
 | 
				
			||||||
 | 
					    const musicData = new Blob([audioData], {type: "audio/ogg"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 读取Meta
 | 
				
			||||||
 | 
					    let tag = await musicMetadata.parseBlob(musicData);
 | 
				
			||||||
 | 
					    const info = util.GetFileInfo(tag.common.artist, tag.common.title, raw_filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 返回
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        status: true,
 | 
				
			||||||
 | 
					        title: info.title,
 | 
				
			||||||
 | 
					        artist: info.artist,
 | 
				
			||||||
 | 
					        ext: 'ogg',
 | 
				
			||||||
 | 
					        album: tag.common.album,
 | 
				
			||||||
 | 
					        picture: util.GetCoverURL(tag),
 | 
				
			||||||
 | 
					        file: URL.createObjectURL(musicData),
 | 
				
			||||||
 | 
					        mime: "audio/ogg"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Mask {
 | 
				
			||||||
 | 
					    constructor(mask) {
 | 
				
			||||||
 | 
					        this.index = -1;
 | 
				
			||||||
 | 
					        this.mask_index = -1;
 | 
				
			||||||
 | 
					        this.mask128 = mask;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NextMask() {
 | 
				
			||||||
 | 
					        this.index++;
 | 
				
			||||||
 | 
					        this.mask_index++;
 | 
				
			||||||
 | 
					        if (this.index === 0x8000 || (this.index > 0x8000 && (this.index + 1) % 0x8000 === 0)) {
 | 
				
			||||||
 | 
					            this.index++;
 | 
				
			||||||
 | 
					            this.mask_index++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.mask_index >= 128) {
 | 
				
			||||||
 | 
					            this.mask_index -= 128;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this.mask128[this.mask_index]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function queryKeyInfo(keyData, headData, filename) {
 | 
				
			||||||
 | 
					    return fetch("https://stats.ixarea.com/collect/mgg/query", {
 | 
				
			||||||
 | 
					        method: "POST",
 | 
				
			||||||
 | 
					        headers: {"Content-Type": "application/json"},
 | 
				
			||||||
 | 
					        body: JSON.stringify({Key: Array.from(keyData), Head: Array.from(headData), Filename: filename}),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user