import { Decrypt as RawDecrypt } from '@/decrypt/raw'; import { DecryptResult } from '@/decrypt/entity'; import { AudioMimeType, BytesHasPrefix, GetArrayBuffer, GetCoverFromFile, GetMetaFromFile } from '@/decrypt/utils'; import { parseBlob as metaParseBlob } from 'music-metadata-browser'; const MagicHeader = [0x69, 0x66, 0x6d, 0x74]; const MagicHeader2 = [0xfe, 0xfe, 0xfe, 0xfe]; const FileTypeMap: { [key: string]: string } = { ' WAV': '.wav', FLAC: '.flac', ' MP3': '.mp3', ' A4M': '.m4a', }; export async function Decrypt(file: File, raw_filename: string, raw_ext: string): Promise { const oriData = new Uint8Array(await GetArrayBuffer(file)); if (!BytesHasPrefix(oriData, MagicHeader) || !BytesHasPrefix(oriData.slice(8, 12), MagicHeader2)) { if (raw_ext === 'xm') { throw Error('此xm文件已损坏'); } else { return await RawDecrypt(file, raw_filename, raw_ext, true); } } let typeText = new TextDecoder().decode(oriData.slice(4, 8)); if (!FileTypeMap.hasOwnProperty(typeText)) { throw Error('未知的.xm文件类型'); } let key = oriData[0xf]; let dataOffset = oriData[0xc] | (oriData[0xd] << 8) | (oriData[0xe] << 16); let audioData = oriData.slice(0x10); let lenAudioData = audioData.length; for (let cur = dataOffset; cur < lenAudioData; ++cur) audioData[cur] = (audioData[cur] - key) ^ 0xff; const ext = FileTypeMap[typeText]; const mime = AudioMimeType[ext]; let musicBlob = new Blob([audioData], { type: mime }); const musicMeta = await metaParseBlob(musicBlob); if (ext === 'wav') { //todo:未知的编码方式 console.info(musicMeta.common); musicMeta.common.album = ''; musicMeta.common.artist = ''; musicMeta.common.title = ''; } const { title, artist } = GetMetaFromFile( raw_filename, musicMeta.common.title, String(musicMeta.common.artists || musicMeta.common.artist), raw_filename.indexOf('_') === -1 ? '-' : '_', ); return { title, artist, ext, mime, album: musicMeta.common.album, picture: GetCoverFromFile(musicMeta), file: URL.createObjectURL(musicBlob), blob: musicBlob, rawExt: 'xm', }; }