mirror of
				https://git.unlock-music.dev/um/web.git
				synced 2025-11-04 11:53:30 +08:00 
			
		
		
		
	refactor(typescript): utils.GetCoverFromFile & utils.GetMetaFromFile
This commit is contained in:
		
							parent
							
								
									4637a3650a
								
							
						
					
					
						commit
						3c0a9e92f9
					
				@ -1,5 +1,11 @@
 | 
				
			|||||||
import {GetFileInfo, GetMetaCoverURL} from "./util";
 | 
					import {
 | 
				
			||||||
import {AudioMimeType, BytesHasPrefix, GetArrayBuffer, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
					    AudioMimeType,
 | 
				
			||||||
 | 
					    BytesHasPrefix,
 | 
				
			||||||
 | 
					    GetArrayBuffer,
 | 
				
			||||||
 | 
					    GetCoverFromFile,
 | 
				
			||||||
 | 
					    GetMetaFromFile,
 | 
				
			||||||
 | 
					    SniffAudioExt
 | 
				
			||||||
 | 
					} from "@/decrypt/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const musicMetadata = require("music-metadata-browser");
 | 
					const musicMetadata = require("music-metadata-browser");
 | 
				
			||||||
const VprHeader = [
 | 
					const VprHeader = [
 | 
				
			||||||
@ -66,17 +72,16 @@ export async function Decrypt(file, raw_filename, raw_ext) {
 | 
				
			|||||||
    const mime = AudioMimeType[ext];
 | 
					    const mime = AudioMimeType[ext];
 | 
				
			||||||
    let musicBlob = new Blob([audioData], {type: mime});
 | 
					    let musicBlob = new Blob([audioData], {type: mime});
 | 
				
			||||||
    const musicMeta = await musicMetadata.parseBlob(musicBlob);
 | 
					    const musicMeta = await musicMetadata.parseBlob(musicBlob);
 | 
				
			||||||
    const info = GetFileInfo(musicMeta.common.artist, musicMeta.common.title, raw_filename);
 | 
					    const {title, artist} = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artist)
 | 
				
			||||||
    const imgUrl = GetMetaCoverURL(musicMeta);
 | 
					 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        status: true,
 | 
					        status: true,
 | 
				
			||||||
        title: info.title,
 | 
					 | 
				
			||||||
        artist: info.artist,
 | 
					 | 
				
			||||||
        album: musicMeta.common.album,
 | 
					        album: musicMeta.common.album,
 | 
				
			||||||
        picture: imgUrl,
 | 
					        picture: GetCoverFromFile(musicMeta),
 | 
				
			||||||
        file: URL.createObjectURL(musicBlob),
 | 
					        file: URL.createObjectURL(musicBlob),
 | 
				
			||||||
        ext,
 | 
					        ext,
 | 
				
			||||||
        mime
 | 
					        mime,
 | 
				
			||||||
 | 
					        title,
 | 
				
			||||||
 | 
					        artist
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,11 @@
 | 
				
			|||||||
import {GetFileInfo, GetMetaCoverURL} from "./util";
 | 
					import {
 | 
				
			||||||
import {AudioMimeType, BytesHasPrefix, GetArrayBuffer, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
					    AudioMimeType,
 | 
				
			||||||
 | 
					    BytesHasPrefix,
 | 
				
			||||||
 | 
					    GetArrayBuffer,
 | 
				
			||||||
 | 
					    GetCoverFromFile,
 | 
				
			||||||
 | 
					    GetMetaFromFile,
 | 
				
			||||||
 | 
					    SniffAudioExt
 | 
				
			||||||
 | 
					} from "@/decrypt/utils.ts";
 | 
				
			||||||
import {Decrypt as RawDecrypt} from "@/decrypt/raw.ts";
 | 
					import {Decrypt as RawDecrypt} from "@/decrypt/raw.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {parseBlob as metaParseBlob} from "music-metadata-browser";
 | 
					import {parseBlob as metaParseBlob} from "music-metadata-browser";
 | 
				
			||||||
@ -32,19 +38,16 @@ export async function Decrypt(file: File, raw_filename: string, _: string) {
 | 
				
			|||||||
    let musicBlob = new Blob([audioData], {type: mime});
 | 
					    let musicBlob = new Blob([audioData], {type: mime});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const musicMeta = await metaParseBlob(musicBlob);
 | 
					    const musicMeta = await metaParseBlob(musicBlob);
 | 
				
			||||||
    const info = GetFileInfo(musicMeta.common.artist, musicMeta.common.title, raw_filename);
 | 
					    const {title, artist} = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artist)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const imgUrl = GetMetaCoverURL(musicMeta);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        status: true,
 | 
					        status: true,
 | 
				
			||||||
        title: info.title,
 | 
					 | 
				
			||||||
        artist: info.artist,
 | 
					 | 
				
			||||||
        ext: ext,
 | 
					 | 
				
			||||||
        album: musicMeta.common.album,
 | 
					        album: musicMeta.common.album,
 | 
				
			||||||
        picture: imgUrl,
 | 
					        picture: GetCoverFromFile(musicMeta),
 | 
				
			||||||
        file: URL.createObjectURL(musicBlob),
 | 
					        file: URL.createObjectURL(musicBlob),
 | 
				
			||||||
        mime: mime
 | 
					        mime,
 | 
				
			||||||
 | 
					        title,
 | 
				
			||||||
 | 
					        artist,
 | 
				
			||||||
 | 
					        ext
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import {AudioMimeType, BytesHasPrefix, GetArrayBuffer, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
					import {AudioMimeType, BytesHasPrefix, GetArrayBuffer, GetMetaFromFile, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CryptoJS = require("crypto-js");
 | 
					const CryptoJS = require("crypto-js");
 | 
				
			||||||
const MetaFlac = require('metaflac-js');
 | 
					const MetaFlac = require('metaflac-js');
 | 
				
			||||||
@ -9,7 +9,6 @@ const musicMetadata = require("music-metadata-browser");
 | 
				
			|||||||
import jimp from 'jimp';
 | 
					import jimp from 'jimp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    GetFileInfo,
 | 
					 | 
				
			||||||
    GetWebImage,
 | 
					    GetWebImage,
 | 
				
			||||||
    WriteMp3Meta
 | 
					    WriteMp3Meta
 | 
				
			||||||
} from "./util"
 | 
					} from "./util"
 | 
				
			||||||
@ -36,11 +35,10 @@ export async function Decrypt(file, raw_filename, _) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const artists = [];
 | 
					    const artists = [];
 | 
				
			||||||
    if (!!musicMeta.artist) musicMeta.artist.forEach(arr => artists.push(arr[0]));
 | 
					    if (!!musicMeta.artist) musicMeta.artist.forEach(arr => artists.push(arr[0]));
 | 
				
			||||||
    const info = GetFileInfo(artists.join("; "), musicMeta.musicName, raw_filename);
 | 
					    const info = GetMetaFromFile(raw_filename, musicMeta.musicName, artists.join("; "))
 | 
				
			||||||
    if (artists.length === 0) artists.push(info.artist);
 | 
					    if (artists.length === 0) artists.push(info.artist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (musicMeta.format === undefined) musicMeta.format = SniffAudioExt(audioData);
 | 
					    if (musicMeta.format === undefined) musicMeta.format = SniffAudioExt(audioData);
 | 
				
			||||||
    console.log(musicMeta)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const imageInfo = await GetWebImage(musicMeta.albumPic);
 | 
					    const imageInfo = await GetWebImage(musicMeta.albumPic);
 | 
				
			||||||
    while (!!imageInfo.buffer && imageInfo.buffer.byteLength >= 16 * 1024 * 1024) {
 | 
					    while (!!imageInfo.buffer && imageInfo.buffer.byteLength >= 16 * 1024 * 1024) {
 | 
				
			||||||
@ -48,12 +46,10 @@ export async function Decrypt(file, raw_filename, _) {
 | 
				
			|||||||
        await img.resize(Math.round(img.getHeight() / 2), jimp.AUTO)
 | 
					        await img.resize(Math.round(img.getHeight() / 2), jimp.AUTO)
 | 
				
			||||||
        imageInfo.buffer = await img.getBufferAsync("image/jpeg")
 | 
					        imageInfo.buffer = await img.getBufferAsync("image/jpeg")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    console.log(imageInfo)
 | 
					 | 
				
			||||||
    const mime = AudioMimeType[musicMeta.format]
 | 
					    const mime = AudioMimeType[musicMeta.format]
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        let musicBlob = new Blob([audioData], {type: mime});
 | 
					        let musicBlob = new Blob([audioData], {type: mime});
 | 
				
			||||||
        const originalMeta = await musicMetadata.parseBlob(musicBlob);
 | 
					        const originalMeta = await musicMetadata.parseBlob(musicBlob);
 | 
				
			||||||
        console.log(originalMeta)
 | 
					 | 
				
			||||||
        let shouldWrite = !originalMeta.common.album && !originalMeta.common.artists && !originalMeta.common.title
 | 
					        let shouldWrite = !originalMeta.common.album && !originalMeta.common.artists && !originalMeta.common.title
 | 
				
			||||||
        if (musicMeta.format === "mp3") {
 | 
					        if (musicMeta.format === "mp3") {
 | 
				
			||||||
            audioData = await WriteMp3Meta(
 | 
					            audioData = await WriteMp3Meta(
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,11 @@
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    GetFileInfo,
 | 
					 | 
				
			||||||
    GetMetaCoverURL,
 | 
					 | 
				
			||||||
    GetWebImage,
 | 
					    GetWebImage,
 | 
				
			||||||
    IXAREA_API_ENDPOINT,
 | 
					    IXAREA_API_ENDPOINT,
 | 
				
			||||||
    WriteMp3Meta
 | 
					    WriteMp3Meta
 | 
				
			||||||
} from "./util";
 | 
					} from "./util";
 | 
				
			||||||
import {QmcMaskCreate58, QmcMaskDetectMflac, QmcMaskDetectMgg, QmcMaskGetDefault} from "./qmcMask";
 | 
					import {QmcMaskCreate58, QmcMaskDetectMflac, QmcMaskDetectMgg, QmcMaskGetDefault} from "./qmcMask";
 | 
				
			||||||
import {fromByteArray as Base64Encode, toByteArray as Base64Decode} from 'base64-js'
 | 
					import {fromByteArray as Base64Encode, toByteArray as Base64Decode} from 'base64-js'
 | 
				
			||||||
import {AudioMimeType, GetArrayBuffer, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
					import {AudioMimeType, GetArrayBuffer, GetCoverFromFile, GetMetaFromFile, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MetaFlac = require('metaflac-js');
 | 
					const MetaFlac = require('metaflac-js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,12 +68,12 @@ export async function Decrypt(file, raw_filename, raw_ext) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const info = GetFileInfo(musicMeta.common.artist, musicMeta.common.title, raw_filename);
 | 
					    const info = GetMetaFromFile(raw_filename, musicMeta.common.title, musicMeta.common.artist)
 | 
				
			||||||
    if (handler.detect) reportKeyUsage(keyData, seed.Matrix128,
 | 
					    if (handler.detect) reportKeyUsage(keyData, seed.Matrix128,
 | 
				
			||||||
        info.artist, info.title, musicMeta.common.album, raw_filename, raw_ext);
 | 
					        info.artist, info.title, musicMeta.common.album, raw_filename, raw_ext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let imgUrl = GetMetaCoverURL(musicMeta);
 | 
					    let imgUrl = GetCoverFromFile(musicMeta);
 | 
				
			||||||
    if (imgUrl === "") {
 | 
					    if (!imgUrl) {
 | 
				
			||||||
        imgUrl = await queryAlbumCoverImage(info.artist, info.title, musicMeta.common.album);
 | 
					        imgUrl = await queryAlbumCoverImage(info.artist, info.title, musicMeta.common.album);
 | 
				
			||||||
        if (imgUrl !== "") {
 | 
					        if (imgUrl !== "") {
 | 
				
			||||||
            const imageInfo = await GetWebImage(imgUrl);
 | 
					            const imageInfo = await GetWebImage(imgUrl);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,7 @@
 | 
				
			|||||||
import {AudioMimeType, GetArrayBuffer, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
					import {AudioMimeType, GetArrayBuffer, GetCoverFromFile, GetMetaFromFile, SniffAudioExt} from "@/decrypt/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {parseBlob as metaParseBlob} from "music-metadata-browser";
 | 
					import {parseBlob as metaParseBlob} from "music-metadata-browser";
 | 
				
			||||||
import {GetMetaCoverURL, GetFileInfo} from "./util";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string, detect: boolean = true) {
 | 
					export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string, detect: boolean = true) {
 | 
				
			||||||
    let ext = raw_ext;
 | 
					    let ext = raw_ext;
 | 
				
			||||||
@ -12,14 +11,15 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string,
 | 
				
			|||||||
        if (ext !== raw_ext) file = new Blob([buffer], {type: AudioMimeType[ext]})
 | 
					        if (ext !== raw_ext) file = new Blob([buffer], {type: AudioMimeType[ext]})
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const tag = await metaParseBlob(file);
 | 
					    const tag = await metaParseBlob(file);
 | 
				
			||||||
    const info = GetFileInfo(tag.common.artist, tag.common.title, raw_filename);
 | 
					    const {title, artist} = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        status: true,
 | 
					        status: true,
 | 
				
			||||||
        title: info.title,
 | 
					        title,
 | 
				
			||||||
        artist: info.artist,
 | 
					        artist,
 | 
				
			||||||
        ext: ext,
 | 
					        ext,
 | 
				
			||||||
        album: tag.common.album,
 | 
					        album: tag.common.album,
 | 
				
			||||||
        picture: GetMetaCoverURL(tag),
 | 
					        picture: GetCoverFromFile(tag),
 | 
				
			||||||
        file: URL.createObjectURL(file),
 | 
					        file: URL.createObjectURL(file),
 | 
				
			||||||
        mime: AudioMimeType[ext]
 | 
					        mime: AudioMimeType[ext]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,17 +19,6 @@ export function GetFileInfo(artist, title, filenameNoExt, separator = "-") {
 | 
				
			|||||||
    return {artist: newArtist, title: newTitle};
 | 
					    return {artist: newArtist, title: newTitle};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @return {string}
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function GetMetaCoverURL(metadata) {
 | 
					 | 
				
			||||||
    let pic_url = "";
 | 
					 | 
				
			||||||
    if (metadata.common.picture !== undefined && metadata.common.picture.length > 0) {
 | 
					 | 
				
			||||||
        let pic = new Blob([metadata.common.picture[0].data], {type: metadata.common.picture[0].format});
 | 
					 | 
				
			||||||
        pic_url = URL.createObjectURL(pic);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return pic_url;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function GetWebImage(pic_url) {
 | 
					export async function GetWebImage(pic_url) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import {IAudioMetadata} from "music-metadata-browser";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const FLAC_HEADER = [0x66, 0x4C, 0x61, 0x43];
 | 
					export const FLAC_HEADER = [0x66, 0x4C, 0x61, 0x43];
 | 
				
			||||||
export const MP3_HEADER = [0x49, 0x44, 0x33];
 | 
					export const MP3_HEADER = [0x49, 0x44, 0x33];
 | 
				
			||||||
export const OGG_HEADER = [0x4F, 0x67, 0x67, 0x53];
 | 
					export const OGG_HEADER = [0x4F, 0x67, 0x67, 0x53];
 | 
				
			||||||
@ -58,3 +60,32 @@ export function GetArrayBuffer(obj: Blob): Promise<ArrayBuffer> {
 | 
				
			|||||||
        reader.readAsArrayBuffer(obj);
 | 
					        reader.readAsArrayBuffer(obj);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GetCoverFromFile(metadata: IAudioMetadata): string {
 | 
				
			||||||
 | 
					    if (metadata.common?.picture && metadata.common.picture.length > 0) {
 | 
				
			||||||
 | 
					        return URL.createObjectURL(new Blob(
 | 
				
			||||||
 | 
					            [metadata.common.picture[0].data],
 | 
				
			||||||
 | 
					            {type: metadata.common.picture[0].format}
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IMusicMetaBasic {
 | 
				
			||||||
 | 
					    title: string
 | 
				
			||||||
 | 
					    artist?: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GetMetaFromFile(filename: string, exist_title?: string, exist_artist?: string, separator = "-")
 | 
				
			||||||
 | 
					    : IMusicMetaBasic {
 | 
				
			||||||
 | 
					    const meta: IMusicMetaBasic = {title: exist_title ?? "", artist: exist_artist}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const items = filename.split(separator);
 | 
				
			||||||
 | 
					    if (items.length > 1) {
 | 
				
			||||||
 | 
					        if (!meta.artist) meta.artist = items[0].trim();
 | 
				
			||||||
 | 
					        if (!meta.title) meta.title = items[1].trim();
 | 
				
			||||||
 | 
					    } else if (items.length === 1) {
 | 
				
			||||||
 | 
					        if (!meta.title) meta.title = items[0].trim();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return meta
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,5 @@
 | 
				
			|||||||
import {GetFileInfo, GetMetaCoverURL} from "./util";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import {Decrypt as RawDecrypt} from "./raw";
 | 
					import {Decrypt as RawDecrypt} from "./raw";
 | 
				
			||||||
import {AudioMimeType, BytesHasPrefix, GetArrayBuffer} from "@/decrypt/utils.ts";
 | 
					import {AudioMimeType, BytesHasPrefix, GetArrayBuffer, GetCoverFromFile, GetMetaFromFile} from "@/decrypt/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const musicMetadata = require("music-metadata-browser");
 | 
					const musicMetadata = require("music-metadata-browser");
 | 
				
			||||||
const MagicHeader = [0x69, 0x66, 0x6D, 0x74]
 | 
					const MagicHeader = [0x69, 0x66, 0x6D, 0x74]
 | 
				
			||||||
@ -47,20 +45,19 @@ export async function Decrypt(file, raw_filename, raw_ext) {
 | 
				
			|||||||
        musicMeta.common.artist = "";
 | 
					        musicMeta.common.artist = "";
 | 
				
			||||||
        musicMeta.common.title = "";
 | 
					        musicMeta.common.title = "";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let _sep = raw_filename.indexOf("_") === -1 ? "-" : "_"
 | 
					    const {title, artist} = GetMetaFromFile(raw_filename,
 | 
				
			||||||
    const info = GetFileInfo(musicMeta.common.artist, musicMeta.common.title, raw_filename, _sep);
 | 
					        musicMeta.common.title, musicMeta.common.artist,
 | 
				
			||||||
 | 
					        raw_filename.indexOf("_") === -1 ? "-" : "_")
 | 
				
			||||||
    const imgUrl = GetMetaCoverURL(musicMeta);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        status: true,
 | 
					        status: true,
 | 
				
			||||||
        title: info.title,
 | 
					        title,
 | 
				
			||||||
        artist: info.artist,
 | 
					        artist,
 | 
				
			||||||
        ext: ext,
 | 
					        ext,
 | 
				
			||||||
 | 
					        mime,
 | 
				
			||||||
        album: musicMeta.common.album,
 | 
					        album: musicMeta.common.album,
 | 
				
			||||||
        picture: imgUrl,
 | 
					        picture: GetCoverFromFile(musicMeta),
 | 
				
			||||||
        file: URL.createObjectURL(musicBlob),
 | 
					        file: URL.createObjectURL(musicBlob),
 | 
				
			||||||
        mime: mime,
 | 
					 | 
				
			||||||
        rawExt: "xm"
 | 
					        rawExt: "xm"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user