KWMv2/酷我 mflac 支持 #35
@ -17,13 +17,17 @@ import {
|
||||
Text,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { kwm2AddKey, kwm2ClearKeys } from '../settingsSlice';
|
||||
import { selectStagingKWMv2Keys } from '../settingsSelector';
|
||||
import { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { MdAdd, MdDeleteForever, MdExpandMore, MdFileUpload } from 'react-icons/md';
|
||||
import { KWMv2EKeyItem } from './KWMv2/KWMv2EKeyItem';
|
||||
|
||||
import { ImportSecretModal } from '~/components/ImportSecretModal';
|
||||
import { MMKVParser } from '~/util/MMKVParser';
|
||||
|
||||
import { kwm2AddKey, kwm2ClearKeys, kwm2ImportKeys } from '../settingsSlice';
|
||||
import { selectStagingKWMv2Keys } from '../settingsSelector';
|
||||
import { KWMv2EKeyItem } from './KWMv2/KWMv2EKeyItem';
|
||||
import type { StagingKWMv2Key } from '../keyFormats';
|
||||
|
||||
export function PanelKWMv2Key() {
|
||||
const toast = useToast();
|
||||
@ -33,12 +37,29 @@ export function PanelKWMv2Key() {
|
||||
|
||||
const addKey = () => dispatch(kwm2AddKey());
|
||||
const clearAll = () => dispatch(kwm2ClearKeys());
|
||||
const handleSecretImport = () => {
|
||||
const handleSecretImport = async (file: File) => {
|
||||
let keys: Omit<StagingKWMv2Key, 'id'>[] | null = null;
|
||||
if (/cn\.kuwo\.player\.mmkv\.defaultconfig/i.test(file.name)) {
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
keys = MMKVParser.parseKuwoEKey(new DataView(fileBuffer));
|
||||
}
|
||||
|
||||
if (keys) {
|
||||
dispatch(kwm2ImportKeys(keys));
|
||||
setShowImportModal(false);
|
||||
toast({
|
||||
title: '尚未实现',
|
||||
title: `导入完成,共导入了 ${keys.length} 个密钥。`,
|
||||
description: '记得按下「保存」来应用。',
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: `不支持的文件:${file.name}`,
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -82,12 +103,12 @@ export function PanelKWMv2Key() {
|
||||
</Box>
|
||||
|
||||
<ImportSecretModal
|
||||
clientName="QQ 音乐"
|
||||
clientName="酷我音乐"
|
||||
show={showImportModal}
|
||||
onClose={() => setShowImportModal(false)}
|
||||
onImport={handleSecretImport}
|
||||
>
|
||||
尚未实现
|
||||
文档缺失
|
||||
</ImportSecretModal>
|
||||
</Flex>
|
||||
);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import type { StagingKWMv2Key } from '~/features/settings/keyFormats';
|
||||
import { formatHex } from './formatHex';
|
||||
|
||||
const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true });
|
||||
@ -85,6 +86,15 @@ export class MMKVParser {
|
||||
return result;
|
||||
}
|
||||
|
||||
public skipContainer() {
|
||||
// Container [
|
||||
// len: int,
|
||||
// data: variant
|
||||
// ]
|
||||
const containerLen = this.readInt();
|
||||
this.offset += containerLen;
|
||||
}
|
||||
|
||||
public static toStringMap(view: DataView): Map<string, string> {
|
||||
const mmkv = new MMKVParser(view);
|
||||
const result = new Map<string, string>();
|
||||
@ -96,7 +106,21 @@ export class MMKVParser {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static parseKuwoEKey(_view: DataView): unknown[] {
|
||||
return [];
|
||||
public static parseKuwoEKey(view: DataView) {
|
||||
const mmkv = new MMKVParser(view);
|
||||
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
||||
while (!mmkv.eof) {
|
||||
const key = mmkv.readString();
|
||||
const idMatch = key.match(/^sec_ekey#(\d+)-(.+)/);
|
||||
if (!idMatch) {
|
||||
mmkv.skipContainer();
|
||||
continue;
|
||||
}
|
||||
|
||||
const [_, rid, quality] = idMatch;
|
||||
const ekey = mmkv.readVariantString();
|
||||
result.push({ rid, quality, ekey });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user