Changed new line and added QT GUI PoC
This commit is contained in:
parent
641d26ce6a
commit
056e0845ef
528
ED2K.py
528
ED2K.py
|
@ -1,257 +1,271 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
#define FT_FILENAME 0x01 // <string>
|
||||
#define FT_FILESIZE 0x02 // <uint32> (or <uint64> when supported)
|
||||
#define FT_FILESIZE_HI 0x3A // <uint32>
|
||||
#define FT_FILETYPE 0x03 // <string>
|
||||
#define FT_FILEFORMAT 0x04 // <string>
|
||||
#define FT_LASTSEENCOMPLETE 0x05 // <uint32>
|
||||
#define TAG_PART_PATH "\x06" // <string>
|
||||
#define TAG_PART_HASH "\x07"
|
||||
#define FT_TRANSFERRED 0x08 // <uint32>
|
||||
#define TAG_TRANSFERRED "\x08" // <uint32>
|
||||
#define FT_GAPSTART 0x09 // <uint32>
|
||||
#define TAG_GAPSTART "\x09" // <uint32>
|
||||
#define FT_GAPEND 0x0A // <uint32>
|
||||
#define TAG_GAPEND "\x0A" // <uint32>
|
||||
#define FT_DESCRIPTION 0x0B // <string>
|
||||
#define TAG_DESCRIPTION "\x0B" // <string>
|
||||
#define TAG_PING "\x0C"
|
||||
#define TAG_FAIL "\x0D"
|
||||
#define TAG_PREFERENCE "\x0E"
|
||||
#define FT_PARTFILENAME 0x12 // <string>
|
||||
//#define FT_PRIORITY 0x13 // Not used anymore
|
||||
#define FT_STATUS 0x14 // <uint32>
|
||||
#define FT_SOURCES 0x15 // <uint32>
|
||||
#define FT_PERMISSIONS 0x16 // <uint32>
|
||||
//#define FT_ULPRIORITY 0x17 // Not used anymore
|
||||
#define FT_DLPRIORITY 0x18 // Was 13
|
||||
#define FT_ULPRIORITY 0x19 // Was 17
|
||||
#define FT_COMPRESSION 0x1A
|
||||
#define FT_CORRUPTED 0x1B
|
||||
#define FT_KADLASTPUBLISHKEY 0x20 // <uint32>
|
||||
#define FT_KADLASTPUBLISHSRC 0x21 // <uint32>
|
||||
#define FT_FLAGS 0x22 // <uint32>
|
||||
#define FT_DL_ACTIVE_TIME 0x23 // <uint32>
|
||||
#define FT_CORRUPTEDPARTS 0x24 // <string>
|
||||
#define FT_DL_PREVIEW 0x25
|
||||
#define FT_KADLASTPUBLISHNOTES 0x26 // <uint32>
|
||||
#define FT_AICH_HASH 0x27
|
||||
#define FT_FILEHASH 0x28
|
||||
#define FT_COMPLETE_SOURCES 0x30 // nr. of sources which share a complete version of the associated file (supported by eserver 16.46+)
|
||||
#define FT_COLLECTIONAUTHOR 0x31
|
||||
#define FT_COLLECTIONAUTHORKEY 0x32
|
||||
#define FT_PUBLISHINFO 0x33 // <uint32>
|
||||
#define FT_LASTSHARED 0x34 // <uint32>
|
||||
#define FT_AICHHASHSET 0x35 // <uint32>
|
||||
#define TAG_KADAICHHASHPUB "\x36" // <AICH Hash>
|
||||
|
||||
// statistic
|
||||
#define FT_ATTRANSFERRED 0x50 // <uint32>
|
||||
#define FT_ATREQUESTED 0x51 // <uint32>
|
||||
#define FT_ATACCEPTED 0x52 // <uint32>
|
||||
#define FT_CATEGORY 0x53 // <uint32>
|
||||
#define FT_ATTRANSFERREDHI 0x54 // <uint32>
|
||||
#define FT_MAXSOURCES 0x55 // <uint32>
|
||||
#define FT_MEDIA_ARTIST 0xD0 // <string>
|
||||
#define TAG_MEDIA_ARTIST "\xD0" // <string>
|
||||
#define FT_MEDIA_ALBUM 0xD1 // <string>
|
||||
#define TAG_MEDIA_ALBUM "\xD1" // <string>
|
||||
#define FT_MEDIA_TITLE 0xD2 // <string>
|
||||
#define TAG_MEDIA_TITLE "\xD2" // <string>
|
||||
#define FT_MEDIA_LENGTH 0xD3 // <uint32> !!!
|
||||
#define TAG_MEDIA_LENGTH "\xD3" // <uint32> !!!
|
||||
#define FT_MEDIA_BITRATE 0xD4 // <uint32>
|
||||
#define TAG_MEDIA_BITRATE "\xD4" // <uint32>
|
||||
#define FT_MEDIA_CODEC 0xD5 // <string>
|
||||
#define TAG_MEDIA_CODEC "\xD5" // <string>
|
||||
#define FT_FILECOMMENT 0xF6 // <string>
|
||||
#define FT_FILERATING 0xF7 // <uint8>
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import binascii
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
MetEntry = namedtuple('met_entry',
|
||||
['Filename', 'ED2KHash', 'LastChanged', 'Filesize', 'Transfered', 'Requested', 'Accepted',
|
||||
'Transfered_HI', 'PartFilename', 'AICHashCount', 'AICHash'])
|
||||
|
||||
METENTRY_FIELDS = ('FT_FILENAME', 'ED2KHASH', 'NUMPARTS', 'LASTCHANGED', 'PARTHASHES', 'FT_FILESIZE',
|
||||
'FT_ATTRANSFERRED', 'FT_ATREQUESTED', 'FT_ATACCEPTED', 'FT_ATTRANSFERREDHI', 'FT_PARTFILENAME',
|
||||
'FT_AICHHASHSET', 'FT_AICH_HASH', 'FT_ULPRIORITY', 'FT_KADLASTPUBLISHSRC')
|
||||
|
||||
HEADER_KNOWN_MET_FILE = b'\x0e'
|
||||
HEADER_PART_MET_FILE = b'\xe0'
|
||||
|
||||
FT_FILENAME = 0x01
|
||||
FT_FILESIZE = 0x02
|
||||
FT_PARTFILENAME = 0x12
|
||||
FT_PERMISSIONS = 0x16
|
||||
FT_ULPRIORITY = 0x19
|
||||
|
||||
FT_KADLASTPUBLISHKEY = 0x20
|
||||
FT_KADLASTPUBLISHSRC = 0x21
|
||||
FT_FLAGS = 0x22
|
||||
FT_KADLASTPUBLISHNOTES = 0x26
|
||||
FT_AICH_HASH = 0x27
|
||||
|
||||
FT_LASTSHARED = 0x34
|
||||
FT_AICHHASHSET = 0x35
|
||||
|
||||
FT_ATTRANSFERRED = 0x50
|
||||
FT_ATREQUESTED = 0x51
|
||||
FT_ATACCEPTED = 0x52
|
||||
FT_ATTRANSFERREDHI = 0x54
|
||||
|
||||
FT_MEDIA_ARTIST = 0xd0
|
||||
FT_MEDIA_ALBUM = 0xd1
|
||||
FT_MEDIA_TITLE = 0xd2
|
||||
FT_MEDIA_LENGTH = 0xd3
|
||||
FT_MEDIA_BITRATE = 0xd4
|
||||
FT_MEDIA_CODEC = 0xd5
|
||||
|
||||
FT_STRING = (
|
||||
0x03, 0x04, 0x06, 0x0b, 0x11, 0x24, 0x28, 0xf6
|
||||
)
|
||||
|
||||
FT_INT = (
|
||||
0x05, 0x08, 0x09, 0x0a, 0x14, 0x15, 0x18, 0x1a, 0x1b, 0x23, 0x25, 0x30, 0x33, 0x53, 0x55, 0xf7
|
||||
)
|
||||
|
||||
def met_readstring(fd):
|
||||
string_len = int.from_bytes(fd.read(2), byteorder='little')
|
||||
return fd.read(string_len).decode('utf-8', errors='replace')
|
||||
|
||||
|
||||
def met_readinteger(fd, size=4):
|
||||
return int.from_bytes(fd.read(size), byteorder='little')
|
||||
|
||||
|
||||
def record_last_changed(fd):
|
||||
return met_readinteger(fd)
|
||||
|
||||
|
||||
def record_read_hash16(fd):
|
||||
aichash = fd.read(16)
|
||||
return binascii.hexlify(aichash).decode('utf-8')
|
||||
|
||||
|
||||
def record_tags(fd):
|
||||
tags = {}
|
||||
tags['TAGCOUNT'] = met_readinteger(fd)
|
||||
print('Tags: {}'.format(tags['TAGCOUNT']))
|
||||
for index in range(tags['TAGCOUNT']):
|
||||
filetag = fd.read(4)
|
||||
if filetag[:3] not in [b'\x02\x01\x00', b'\x03\x01\x00']:
|
||||
print('<<< Premature end of record at offset 0x{:08X}'.format(fd.tell()))
|
||||
return tags
|
||||
tagid = filetag[-1]
|
||||
if tagid == FT_FILENAME:
|
||||
tags['FT_FILENAME'] = met_readstring(fd)
|
||||
elif tagid == FT_FILESIZE:
|
||||
tags['FT_FILESIZE'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATTRANSFERRED:
|
||||
tags['FT_ATTRANSFERRED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATREQUESTED:
|
||||
tags['FT_ATREQUESTED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATACCEPTED:
|
||||
tags['FT_ATACCEPTED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATTRANSFERREDHI:
|
||||
tags['FT_ATTRANSFERREDHI'] = met_readinteger(fd)
|
||||
elif tagid == FT_ULPRIORITY:
|
||||
tags['FT_ULPRIORITY'] = met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHSRC:
|
||||
tags['FT_KADLASTPUBLISHSRC'] = met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHNOTES:
|
||||
print('FT_KADLASTPUBLISHNOTES')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_FLAGS:
|
||||
print('FT_FLAGS')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_PERMISSIONS:
|
||||
print('FT_PERMISSIONS')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHKEY:
|
||||
print('FT_KADLASTPUBLISHKEY')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_AICH_HASH:
|
||||
tags['FT_AICH_HASH'] = met_readstring(fd)
|
||||
elif tagid == FT_LASTSHARED:
|
||||
tags['FT_LASTSHARED'] = met_readinteger(fd)
|
||||
elif tagid == FT_AICHHASHSET:
|
||||
tags['FT_AICHHASHSET'] = met_readinteger(fd, 1)
|
||||
elif tagid == FT_PARTFILENAME:
|
||||
tags['FT_PARTFILENAME'] = met_readstring(fd)
|
||||
elif tagid == FT_MEDIA_LENGTH:
|
||||
print('Media Length: {}'.format(met_readinteger(fd)))
|
||||
elif tagid == FT_MEDIA_CODEC:
|
||||
print('Media Codec: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_BITRATE:
|
||||
print('Media Bitrate: {}'.format(met_readinteger(fd)))
|
||||
elif tagid == FT_MEDIA_TITLE:
|
||||
print('Media Title: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_ARTIST:
|
||||
print('Media Artist: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_ALBUM:
|
||||
print('Media Album: {}'.format(met_readstring(fd)))
|
||||
elif tagid in FT_STRING:
|
||||
print('... Reading data with tag: {}'.format(tagid))
|
||||
met_readstring(fd)
|
||||
elif tagid in FT_INT:
|
||||
print('... Reading data with tag: {}'.format(tagid))
|
||||
met_readstring(fd)
|
||||
return tags
|
||||
|
||||
|
||||
def record_num_parts(fd):
|
||||
return met_readinteger(fd, 2)
|
||||
|
||||
|
||||
def load_record(fd):
|
||||
met_tags = {}
|
||||
|
||||
met_tags['LASTCHANGED'] = record_last_changed(fd)
|
||||
met_tags['ED2KHASH'] = record_read_hash16(fd)
|
||||
met_tags['NUMPARTS'] = record_num_parts(fd)
|
||||
partshashes = []
|
||||
for i in range(met_tags['NUMPARTS']):
|
||||
partshashes.append(record_read_hash16(fd))
|
||||
met_tags['PARTHASHES'] = partshashes
|
||||
met_tags.update(record_tags(fd))
|
||||
|
||||
for field in METENTRY_FIELDS:
|
||||
if field not in met_tags:
|
||||
met_tags[field] = 0
|
||||
#print(met_tags)
|
||||
metentry = MetEntry(met_tags['FT_FILENAME'], met_tags['ED2KHASH'], met_tags['LASTCHANGED'], met_tags['FT_FILESIZE'],
|
||||
met_tags['FT_ATTRANSFERRED'], met_tags['FT_ATREQUESTED'], met_tags['FT_ATACCEPTED'],
|
||||
met_tags['FT_ATTRANSFERREDHI'], met_tags['FT_PARTFILENAME'], met_tags['FT_AICHHASHSET'],
|
||||
met_tags['PARTHASHES'])
|
||||
print(metentry)
|
||||
return metentry
|
||||
|
||||
|
||||
def load_knownfiles(filename):
|
||||
with open(filename, 'rb') as fd:
|
||||
magic = fd.read(1)
|
||||
if os.path.basename(filename) == 'known.met':
|
||||
count = int.from_bytes(fd.read(4), byteorder='little')
|
||||
print('Number of records: {}'.format(count))
|
||||
if magic == HEADER_KNOWN_MET_FILE:
|
||||
for index in range(count):
|
||||
print('>>> [{}] NEW RECORD ***'.format(index+1))
|
||||
yield load_record(fd)
|
||||
elif magic == HEADER_PART_MET_FILE:
|
||||
print('>>> [{}] NEW RECORD ***'.format(0))
|
||||
yield load_record(fd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
load_knownfiles('.\\data\\known.met')
|
||||
# load_knownfiles('.\\data\\008.part.met')
|
||||
#load_knownfiles(sys.argv[-1])
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
#define FT_FILENAME 0x01 // <string>
|
||||
#define FT_FILESIZE 0x02 // <uint32> (or <uint64> when supported)
|
||||
#define FT_FILESIZE_HI 0x3A // <uint32>
|
||||
#define FT_FILETYPE 0x03 // <string>
|
||||
#define FT_FILEFORMAT 0x04 // <string>
|
||||
#define FT_LASTSEENCOMPLETE 0x05 // <uint32>
|
||||
#define TAG_PART_PATH "\x06" // <string>
|
||||
#define TAG_PART_HASH "\x07"
|
||||
#define FT_TRANSFERRED 0x08 // <uint32>
|
||||
#define TAG_TRANSFERRED "\x08" // <uint32>
|
||||
#define FT_GAPSTART 0x09 // <uint32>
|
||||
#define TAG_GAPSTART "\x09" // <uint32>
|
||||
#define FT_GAPEND 0x0A // <uint32>
|
||||
#define TAG_GAPEND "\x0A" // <uint32>
|
||||
#define FT_DESCRIPTION 0x0B // <string>
|
||||
#define TAG_DESCRIPTION "\x0B" // <string>
|
||||
#define TAG_PING "\x0C"
|
||||
#define TAG_FAIL "\x0D"
|
||||
#define TAG_PREFERENCE "\x0E"
|
||||
#define FT_PARTFILENAME 0x12 // <string>
|
||||
//#define FT_PRIORITY 0x13 // Not used anymore
|
||||
#define FT_STATUS 0x14 // <uint32>
|
||||
#define FT_SOURCES 0x15 // <uint32>
|
||||
#define FT_PERMISSIONS 0x16 // <uint32>
|
||||
//#define FT_ULPRIORITY 0x17 // Not used anymore
|
||||
#define FT_DLPRIORITY 0x18 // Was 13
|
||||
#define FT_ULPRIORITY 0x19 // Was 17
|
||||
#define FT_COMPRESSION 0x1A
|
||||
#define FT_CORRUPTED 0x1B
|
||||
#define FT_KADLASTPUBLISHKEY 0x20 // <uint32>
|
||||
#define FT_KADLASTPUBLISHSRC 0x21 // <uint32>
|
||||
#define FT_FLAGS 0x22 // <uint32>
|
||||
#define FT_DL_ACTIVE_TIME 0x23 // <uint32>
|
||||
#define FT_CORRUPTEDPARTS 0x24 // <string>
|
||||
#define FT_DL_PREVIEW 0x25
|
||||
#define FT_KADLASTPUBLISHNOTES 0x26 // <uint32>
|
||||
#define FT_AICH_HASH 0x27
|
||||
#define FT_FILEHASH 0x28
|
||||
#define FT_COMPLETE_SOURCES 0x30 // nr. of sources which share a complete version of the associated file (supported by eserver 16.46+)
|
||||
#define FT_COLLECTIONAUTHOR 0x31
|
||||
#define FT_COLLECTIONAUTHORKEY 0x32
|
||||
#define FT_PUBLISHINFO 0x33 // <uint32>
|
||||
#define FT_LASTSHARED 0x34 // <uint32>
|
||||
#define FT_AICHHASHSET 0x35 // <uint32>
|
||||
#define TAG_KADAICHHASHPUB "\x36" // <AICH Hash>
|
||||
|
||||
// statistic
|
||||
#define FT_ATTRANSFERRED 0x50 // <uint32>
|
||||
#define FT_ATREQUESTED 0x51 // <uint32>
|
||||
#define FT_ATACCEPTED 0x52 // <uint32>
|
||||
#define FT_CATEGORY 0x53 // <uint32>
|
||||
#define FT_ATTRANSFERREDHI 0x54 // <uint32>
|
||||
#define FT_MAXSOURCES 0x55 // <uint32>
|
||||
#define FT_MEDIA_ARTIST 0xD0 // <string>
|
||||
#define TAG_MEDIA_ARTIST "\xD0" // <string>
|
||||
#define FT_MEDIA_ALBUM 0xD1 // <string>
|
||||
#define TAG_MEDIA_ALBUM "\xD1" // <string>
|
||||
#define FT_MEDIA_TITLE 0xD2 // <string>
|
||||
#define TAG_MEDIA_TITLE "\xD2" // <string>
|
||||
#define FT_MEDIA_LENGTH 0xD3 // <uint32> !!!
|
||||
#define TAG_MEDIA_LENGTH "\xD3" // <uint32> !!!
|
||||
#define FT_MEDIA_BITRATE 0xD4 // <uint32>
|
||||
#define TAG_MEDIA_BITRATE "\xD4" // <uint32>
|
||||
#define FT_MEDIA_CODEC 0xD5 // <string>
|
||||
#define TAG_MEDIA_CODEC "\xD5" // <string>
|
||||
#define FT_FILECOMMENT 0xF6 // <string>
|
||||
#define FT_FILERATING 0xF7 // <uint8>
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import binascii
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
#MetEntry = namedtuple('met_entry',
|
||||
# ['Filename', 'ED2KHash', 'LastChanged', 'Filesize', 'Transfered', 'Requested', 'Accepted',
|
||||
# 'Transfered_HI', 'PartFilename', 'AICHashCount', 'AICHash'])
|
||||
|
||||
METENTRY_FIELDS = ('FT_FILENNAME', 'ED2KHASH', 'NUMPARTS', 'LASTCHANGED', 'PARTHASHES', 'FT_FILESIZE',
|
||||
'FT_ATTRANSFERRED', 'FT_ATREQUESTED', 'FT_ATACCEPTED', 'FT_ATTRANSFERREDHI', 'FT_PARTFILENAME',
|
||||
'FT_AICHHASHSET', 'FT_AICH_HASH', 'FT_ULPRIORITY', 'FT_KADLASTPUBLISHSRC')
|
||||
MetEntry = namedtuple('met_entry', METENTRY_FIELDS)
|
||||
|
||||
HEADER_KNOWN_MET_FILE = b'\x0e'
|
||||
HEADER_PART_MET_FILE = b'\xe0'
|
||||
|
||||
FT_FILENAME = 0x01
|
||||
FT_FILESIZE = 0x02
|
||||
FT_PARTFILENAME = 0x12
|
||||
FT_PERMISSIONS = 0x16
|
||||
FT_ULPRIORITY = 0x19
|
||||
|
||||
FT_KADLASTPUBLISHKEY = 0x20
|
||||
FT_KADLASTPUBLISHSRC = 0x21
|
||||
FT_FLAGS = 0x22
|
||||
FT_KADLASTPUBLISHNOTES = 0x26
|
||||
FT_AICH_HASH = 0x27
|
||||
|
||||
FT_LASTSHARED = 0x34
|
||||
FT_AICHHASHSET = 0x35
|
||||
|
||||
FT_ATTRANSFERRED = 0x50
|
||||
FT_ATREQUESTED = 0x51
|
||||
FT_ATACCEPTED = 0x52
|
||||
FT_ATTRANSFERREDHI = 0x54
|
||||
|
||||
FT_MEDIA_ARTIST = 0xd0
|
||||
FT_MEDIA_ALBUM = 0xd1
|
||||
FT_MEDIA_TITLE = 0xd2
|
||||
FT_MEDIA_LENGTH = 0xd3
|
||||
FT_MEDIA_BITRATE = 0xd4
|
||||
FT_MEDIA_CODEC = 0xd5
|
||||
|
||||
FT_STRING = (
|
||||
0x03, 0x04, 0x06, 0x0b, 0x11, 0x24, 0x28, 0xf6
|
||||
)
|
||||
|
||||
FT_INT = (
|
||||
0x05, 0x08, 0x09, 0x0a, 0x14, 0x15, 0x18, 0x1a, 0x1b, 0x23, 0x25, 0x30, 0x33, 0x53, 0x55, 0xf7
|
||||
)
|
||||
|
||||
def met_readstring(fd):
|
||||
string_len = int.from_bytes(fd.read(2), byteorder='little')
|
||||
return fd.read(string_len).decode('utf-8', errors='replace')
|
||||
|
||||
|
||||
def met_readinteger(fd, size=4):
|
||||
return int.from_bytes(fd.read(size), byteorder='little')
|
||||
|
||||
|
||||
def record_last_changed(fd):
|
||||
return met_readinteger(fd)
|
||||
|
||||
|
||||
def record_read_hash16(fd):
|
||||
aichash = fd.read(16)
|
||||
return binascii.hexlify(aichash).decode('utf-8')
|
||||
|
||||
|
||||
def record_tags(fd):
|
||||
tags = {}
|
||||
tags['TAGCOUNT'] = met_readinteger(fd)
|
||||
# print('Tags: {}'.format(tags['TAGCOUNT']))
|
||||
for index in range(tags['TAGCOUNT']):
|
||||
filetag = fd.read(4)
|
||||
if filetag[:3] not in [b'\x02\x01\x00', b'\x03\x01\x00']:
|
||||
print('<<< Premature end of record at offset 0x{:08X}'.format(fd.tell()))
|
||||
return tags
|
||||
tagid = filetag[-1]
|
||||
if tagid == FT_FILENAME:
|
||||
tags['FT_FILENAME'] = met_readstring(fd)
|
||||
elif tagid == FT_FILESIZE:
|
||||
tags['FT_FILESIZE'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATTRANSFERRED:
|
||||
tags['FT_ATTRANSFERRED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATREQUESTED:
|
||||
tags['FT_ATREQUESTED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATACCEPTED:
|
||||
tags['FT_ATACCEPTED'] = met_readinteger(fd)
|
||||
elif tagid == FT_ATTRANSFERREDHI:
|
||||
tags['FT_ATTRANSFERREDHI'] = met_readinteger(fd)
|
||||
elif tagid == FT_ULPRIORITY:
|
||||
tags['FT_ULPRIORITY'] = met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHSRC:
|
||||
tags['FT_KADLASTPUBLISHSRC'] = met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHNOTES:
|
||||
print('FT_KADLASTPUBLISHNOTES')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_FLAGS:
|
||||
print('FT_FLAGS')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_PERMISSIONS:
|
||||
print('FT_PERMISSIONS')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_KADLASTPUBLISHKEY:
|
||||
print('FT_KADLASTPUBLISHKEY')
|
||||
met_readinteger(fd)
|
||||
elif tagid == FT_AICH_HASH:
|
||||
tags['FT_AICH_HASH'] = met_readstring(fd)
|
||||
elif tagid == FT_LASTSHARED:
|
||||
tags['FT_LASTSHARED'] = met_readinteger(fd)
|
||||
elif tagid == FT_AICHHASHSET:
|
||||
tags['FT_AICHHASHSET'] = met_readinteger(fd, 1)
|
||||
elif tagid == FT_PARTFILENAME:
|
||||
tags['FT_PARTFILENAME'] = met_readstring(fd)
|
||||
elif tagid == FT_MEDIA_LENGTH:
|
||||
print('Media Length: {}'.format(met_readinteger(fd)))
|
||||
elif tagid == FT_MEDIA_CODEC:
|
||||
print('Media Codec: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_BITRATE:
|
||||
print('Media Bitrate: {}'.format(met_readinteger(fd)))
|
||||
elif tagid == FT_MEDIA_TITLE:
|
||||
print('Media Title: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_ARTIST:
|
||||
print('Media Artist: {}'.format(met_readstring(fd)))
|
||||
elif tagid == FT_MEDIA_ALBUM:
|
||||
print('Media Album: {}'.format(met_readstring(fd)))
|
||||
elif tagid in FT_STRING:
|
||||
print('... Reading data with tag: {}'.format(tagid))
|
||||
met_readstring(fd)
|
||||
elif tagid in FT_INT:
|
||||
print('... Reading data with tag: {}'.format(tagid))
|
||||
met_readstring(fd)
|
||||
return tags
|
||||
|
||||
|
||||
def record_num_parts(fd):
|
||||
return met_readinteger(fd, 2)
|
||||
|
||||
|
||||
def load_record(fd):
|
||||
met_tags = {}
|
||||
|
||||
met_tags['LASTCHANGED'] = record_last_changed(fd)
|
||||
met_tags['ED2KHASH'] = record_read_hash16(fd)
|
||||
met_tags['NUMPARTS'] = record_num_parts(fd)
|
||||
partshashes = []
|
||||
for i in range(met_tags['NUMPARTS']):
|
||||
partshashes.append(record_read_hash16(fd))
|
||||
met_tags['PARTHASHES'] = partshashes
|
||||
met_tags.update(record_tags(fd))
|
||||
|
||||
for field in METENTRY_FIELDS:
|
||||
if field not in met_tags:
|
||||
met_tags[field] = None
|
||||
# print(met_tags)
|
||||
# TODO: use new one
|
||||
metentry = MetEntry(met_tags['FT_FILENAME'],
|
||||
met_tags['ED2KHASH'],
|
||||
met_tags['NUMPARTS'],
|
||||
met_tags['LASTCHANGED'],
|
||||
met_tags['PARTHASHES'],
|
||||
met_tags['FT_FILESIZE'],
|
||||
met_tags['FT_ATTRANSFERRED'],
|
||||
met_tags['FT_ATREQUESTED'],
|
||||
met_tags['FT_ATACCEPTED'],
|
||||
met_tags['FT_ATTRANSFERREDHI'],
|
||||
met_tags['FT_PARTFILENAME'],
|
||||
met_tags['FT_AICHHASHSET'],
|
||||
met_tags['FT_AICH_HASH'],
|
||||
met_tags['FT_ULPRIORITY'],
|
||||
met_tags['FT_KADLASTPUBLISHSRC']
|
||||
)
|
||||
print(metentry)
|
||||
return metentry
|
||||
|
||||
|
||||
def load_knownfiles(filename):
|
||||
with open(filename, 'rb') as fd:
|
||||
magic = fd.read(1)
|
||||
if os.path.basename(filename) == 'known.met':
|
||||
count = int.from_bytes(fd.read(4), byteorder='little')
|
||||
# print('Number of records: {}'.format(count))
|
||||
if magic == HEADER_KNOWN_MET_FILE:
|
||||
for index in range(count):
|
||||
# print('>>> [{}] NEW RECORD ***'.format(index+1))
|
||||
yield load_record(fd)
|
||||
elif magic == HEADER_PART_MET_FILE:
|
||||
# print('>>> [{}] NEW RECORD ***'.format(0))
|
||||
yield load_record(fd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
load_knownfiles('.\\data\\known.met')
|
||||
# load_knownfiles('.\\data\\008.part.met')
|
||||
#load_knownfiles(sys.argv[-1])
|
||||
|
|
|
@ -24,19 +24,21 @@ class Ui_MainWindow(object):
|
|||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.tableView = QtWidgets.QTableView(self.tab)
|
||||
self.tableView.setEnabled(True)
|
||||
self.tableWidget = QtWidgets.QTableWidget(self.tab)
|
||||
self.tableWidget.setEnabled(True)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.tableView.sizePolicy().hasHeightForWidth())
|
||||
self.tableView.setSizePolicy(sizePolicy)
|
||||
self.tableView.setMinimumSize(QtCore.QSize(243, 100))
|
||||
self.tableView.setMaximumSize(QtCore.QSize(16777215, 100))
|
||||
self.tableView.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.tableView.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||
self.tableView.setObjectName("tableView")
|
||||
self.horizontalLayout.addWidget(self.tableView)
|
||||
sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth())
|
||||
self.tableWidget.setSizePolicy(sizePolicy)
|
||||
self.tableWidget.setMinimumSize(QtCore.QSize(243, 100))
|
||||
self.tableWidget.setMaximumSize(QtCore.QSize(16777215, 100))
|
||||
self.tableWidget.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.tableWidget.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||
self.tableWidget.setObjectName("tableWidget")
|
||||
self.tableWidget.setColumnCount(0)
|
||||
self.tableWidget.setRowCount(0)
|
||||
self.horizontalLayout.addWidget(self.tableWidget)
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.lblSearch = QtWidgets.QLabel(self.tab)
|
||||
|
@ -83,6 +85,13 @@ class Ui_MainWindow(object):
|
|||
self.statusBar = QtWidgets.QStatusBar(MainWindow)
|
||||
self.statusBar.setObjectName("statusBar")
|
||||
MainWindow.setStatusBar(self.statusBar)
|
||||
self.actionFile_open = QtWidgets.QAction(MainWindow)
|
||||
self.actionFile_open.setObjectName("actionFile_open")
|
||||
self.actionExit = QtWidgets.QAction(MainWindow)
|
||||
self.actionExit.setObjectName("actionExit")
|
||||
self.menuFile.addAction(self.actionFile_open)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.actionExit)
|
||||
self.menubar.addAction(self.menuFile.menuAction())
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
|
@ -96,4 +105,6 @@ class Ui_MainWindow(object):
|
|||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Tab 2"))
|
||||
self.menuFile.setTitle(_translate("MainWindow", "File"))
|
||||
self.actionFile_open.setText(_translate("MainWindow", "File open"))
|
||||
self.actionExit.setText(_translate("MainWindow", "Exit"))
|
||||
|
||||
|
|
15
main.ui
15
main.ui
|
@ -25,7 +25,7 @@
|
|||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView">
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -129,10 +129,23 @@
|
|||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionFile_open"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionFile_open">
|
||||
<property name="text">
|
||||
<string>File open</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow
|
||||
import locale
|
||||
from PyQt5.QtCore import Qt, QDateTime, QLocale
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QAbstractItemView, QTableWidgetItem
|
||||
from PyQt5.QtGui import QStandardItemModel
|
||||
from MuleAnalyzerUI import Ui_MainWindow
|
||||
|
||||
|
@ -10,8 +11,24 @@ from ED2K import load_knownfiles
|
|||
|
||||
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
|
||||
TreeHeaders = ('Filename', 'ED2K Hash', 'Last Changed', 'Filesize', 'Transfered', 'Requested', 'Accepted',
|
||||
'Transfered (HI)', 'Part Filename', 'Number of Parts', 'Parts Hashes')
|
||||
# Todo: Replace TreeHeaders
|
||||
Headers = (
|
||||
('ID', None, None, 0, Qt.AlignRight),
|
||||
('Filename', 'FT_FILENAME', str, '', Qt.AlignLeft),
|
||||
('ED2K Hash', 'ED2KHASH', str, '', Qt.AlignLeft),
|
||||
('Hashset', None, None, '', Qt.AlignLeft),
|
||||
('Last Changed', 'LASTCHANGED', 'Never', QDateTime, Qt.AlignLeft),
|
||||
('Filesize', 'FT_FILESIZE', int, 0, Qt.AlignRight),
|
||||
('Transfered', 'FT_ATTRANSFERRED', int, 0, Qt.AlignRight),
|
||||
('Transfered (HI)', 'FT_ATTRANSFERREDHI', int, 0, Qt.AlignRight),
|
||||
('Requested', 'FT_ATREQUESTED', int, 0, Qt.AlignRight),
|
||||
('Accepted', 'FT_ATACCEPTED', int, 0, Qt.AlignRight),
|
||||
('AICHashes', 'FT_AICHHASHSET', str, '', Qt.AlignLeft),
|
||||
('AICHash', 'FT_AICH_HASH', str, '', Qt.AlignLeft),
|
||||
('Part Filename', 'FT_PARTFILENAME', str, '', Qt.AlignLeft),
|
||||
('Number of Parts', 'NUMPARTS', int, 0, Qt.AlignRight),
|
||||
('Parts Hash', 'PARTHASHES', list, '', Qt.AlignLeft),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(MainWindow, self).__init__()
|
||||
|
@ -21,35 +38,95 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
self.treeView.setModel(self.treeModel)
|
||||
self.treeView.setRootIsDecorated(False)
|
||||
self.treeView.setAlternatingRowColors(True)
|
||||
self.treeView.setSortingEnabled(True)
|
||||
self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
#self.treeView.setSelectionMode(QAbstractItemView.MultiSelection)
|
||||
|
||||
# TODO
|
||||
self.loadMetFile(None)
|
||||
self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
|
||||
self.actionFile_open.setShortcut('Ctrl+O')
|
||||
self.actionFile_open.triggered.connect(self.slot_load_met_file)
|
||||
self.actionExit.triggered.connect(self.close)
|
||||
|
||||
def createED2KModel(self, parent):
|
||||
model = QStandardItemModel(0, len(self.TreeHeaders), parent)
|
||||
for i, title in enumerate(self.TreeHeaders):
|
||||
model.setHeaderData(i, Qt.Horizontal, title)
|
||||
model = QStandardItemModel(0, len(self.Headers), parent)
|
||||
for i, fields in enumerate(self.Headers):
|
||||
model.setHeaderData(i, Qt.Horizontal, fields[0])
|
||||
return model
|
||||
|
||||
def addED2K(self, model, metinfo):
|
||||
model.insertRow(0)
|
||||
model.setData(model.index(0, 0), metinfo.Filename)
|
||||
for i, field in enumerate(self.Headers):
|
||||
print(i, field)
|
||||
if field[2] is None:
|
||||
if i == 0:
|
||||
root = self.treeModel.invisibleRootItem()
|
||||
row_count = root.rowCount()
|
||||
model.setData(model.index(0, i), row_count+1)
|
||||
if i == 3:
|
||||
# TODO Hash lookup
|
||||
model.setData(model.index(0, i), '<TODO>')
|
||||
else:
|
||||
value = getattr(metinfo, field[1]) or field[3]
|
||||
if field[2] is QDateTime:
|
||||
last_changed = QDateTime.fromSecsSinceEpoch(value, 0)
|
||||
print(last_changed.toString('dd.MM.yyyy hh:mm:ss'))
|
||||
model.setData(model.index(0, i), last_changed.toString('dd.MM.yyyy hh:mm:ss'))
|
||||
elif field[2] is int:
|
||||
print(value)
|
||||
model.setData(model.index(0, i), '{0:,}'.format(value))
|
||||
elif field[2] is list:
|
||||
print(''.join(value))
|
||||
model.setData(model.index(0, i), ''.join(value))
|
||||
else:
|
||||
print(value)
|
||||
model.setData(model.index(0, i), value)
|
||||
model.item(0, i).setTextAlignment(field[4])
|
||||
|
||||
"""model.setData(model.index(0, 0), metinfo.Filename)
|
||||
model.setData(model.index(0, 1), metinfo.ED2KHash)
|
||||
model.setData(model.index(0, 2), metinfo.LastChanged)
|
||||
model.setData(model.index(0, 3), metinfo.Filesize)
|
||||
model.setData(model.index(0, 4), metinfo.Transfered)
|
||||
model.setData(model.index(0, 5), metinfo.Requested)
|
||||
model.setData(model.index(0, 6), metinfo.Accepted)
|
||||
model.setData(model.index(0, 7), metinfo.Transfered_HI)
|
||||
last_changed = QDateTime.fromSecsSinceEpoch(metinfo.LastChanged)
|
||||
model.setData(model.index(0, 2), last_changed.toString('dd.MM.yyyy hh:mm:ss'))
|
||||
model.setData(model.index(0, 3), '{0:,}'.format(metinfo.Filesize))
|
||||
model.item(0, 3).setTextAlignment(Qt.AlignRight)
|
||||
model.setData(model.index(0, 4), '{0:,}'.format(metinfo.Transfered))
|
||||
model.item(0, 4).setTextAlignment(Qt.AlignRight)
|
||||
model.setData(model.index(0, 5), '{0:,}'.format(metinfo.Requested))
|
||||
model.item(0, 5).setTextAlignment(Qt.AlignRight)
|
||||
model.setData(model.index(0, 6), '{0:,}'.format(metinfo.Accepted))
|
||||
model.item(0, 6).setTextAlignment(Qt.AlignRight)
|
||||
model.setData(model.index(0, 7), '{0:,}'.format(metinfo.Transfered_HI))
|
||||
model.item(0, 7).setTextAlignment(Qt.AlignRight)
|
||||
model.setData(model.index(0, 8), metinfo.PartFilename)
|
||||
model.setData(model.index(0, 9), metinfo.AICHashCount)
|
||||
model.setData(model.index(0, 10), metinfo.AICHash)
|
||||
|
||||
model.item(0, 9).setTextAlignment(Qt.AlignRight)
|
||||
print(metinfo.AICHash)
|
||||
model.setData(model.index(0, 10), metinfo.AICHash)"""
|
||||
|
||||
def loadMetFile(self, filename):
|
||||
for met_entry in load_knownfiles('.\\data\\known.met'):
|
||||
for met_entry in load_knownfiles(filename):
|
||||
self.addED2K(self.treeModel, met_entry)
|
||||
|
||||
def slot_load_met_file(self):
|
||||
options = QFileDialog.Options()
|
||||
options |= QFileDialog.DontUseNativeDialog
|
||||
files, _ = QFileDialog.getOpenFileNames(self, 'Open .met files...', '', 'MET Files (*.met);;All Files (*)',
|
||||
options=options)
|
||||
for filename in files:
|
||||
self.loadMetFile(filename)
|
||||
|
||||
root = self.treeModel.invisibleRootItem()
|
||||
row_count = root.rowCount()
|
||||
transfered = 0
|
||||
for i in range(row_count):
|
||||
row = self.treeModel.item(i, column=4)
|
||||
transfered += int(row.text().replace(',', ''))
|
||||
self.tableWidget.setRowCount(1)
|
||||
self.tableWidget.setColumnCount(2)
|
||||
self.tableWidget.setItem(0, 0, QTableWidgetItem('Transfered overall:'))
|
||||
self.tableWidget.setItem(0, 1, QTableWidgetItem(str('{0:,}'.format(transfered))))
|
||||
|
||||
|
||||
|
||||
def main(argv):
|
||||
app = QApplication(argv)
|
||||
|
|
Loading…
Reference in New Issue