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