summaryrefslogtreecommitdiffstats
path: root/bindings/python/gtkpod.py
blob: 83f460b7ab707db24e066becec6e4fc28a62d0d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"""Read and write Gtkpod extended info files."""

import sha
import os
import socket

# This file is originally stolen from pypod-0.5.0
# http://superduper.net/index.py?page=pypod
# I hope that's ok, both works are GPL.

hostname = socket.gethostname()

class ParseError(Exception):
    """Exception for parse errors."""
    pass

class SyncError(Exception):
    """Exception for sync errors."""
    pass

def sha1_hash(filename):
    """Return an SHA1 hash on the first 16k of a file."""
    import struct
    # only hash the first 16k
    hash_len = 4*4096
    hash = sha.sha()
    size = os.path.getsize(filename)
    hash.update(struct.pack("<L", size))
    hash.update(open(filename).read(hash_len))
    return hash.hexdigest()

def write(filename, db, itunesdb_file):
    """Save extended info to a file.

    db is a gpod.Database instance

    Extended info is written for the iTunesDB specified in
    itunesdb_file

    """

    file = open(filename, "w")

    def write_pair(name, value):
        value = unicode(value).encode("utf-8")
        file.write("=".join([name, value]))
        file.write('\n')

    write_pair("itunesdb_hash", sha1_hash(itunesdb_file))
    write_pair("version", "0.99.9")

    for track in db:
        write_pair("id", track['id'])
        if not track['userdata']:
            track['userdata'] = {}
        track['userdata']['filename_ipod'] = track['ipod_path']
        try:
            hash_name = 'sha1_hash'
            del track['userdata'][hash_name]
        except KeyError:
            # recent gpod uses sha1_hash, older uses md5_hash            
            hash_name = 'md5_hash'
            del track['userdata'][hash_name]
        if track['userdata'].has_key('filename_locale') and not track['userdata'].has_key(hash_name):
            if os.path.exists(track['userdata']['filename_locale']):
                track['userdata'][hash_name] = sha1_hash(
                    track['userdata']['filename_locale'])
        [write_pair(i[0],i[1]) for i in track['userdata'].items()]

    write_pair("id", "xxx")

def parse(filename, db, itunesdb_file=None):
    """Load extended info from a file.

    db is a gpod.Database instance

    If itunesdb_file is set and it's hash is valid some expensive
    checks are skipped.

    """

    tracks_by_id  = {}
    tracks_by_sha = {}    
    id = 0
    ext_hash_valid = True

    for track in db:
        track['userdata'] = {}

    for track in db:
        tracks_by_id[track['id']] = track

    track = None
    file = open(filename)
    ext_data = {}
    ext_block = None
    for line in file:
        parts = line.strip().split("=", 1)
        if len(parts) != 2:
            print parts
        name, value = parts
        if name == "id":
            if ext_block:
                ext_data[id] = ext_block
            if value != 'xxx':
                id = int(value)
                ext_block = {}
        elif name == "version":
            pass
        elif name == "itunesdb_hash":
            if itunesdb_file and sha1_hash(itunesdb_file) != value:
                ext_hash_valid = False
        else:
            ext_block[name] = value

    if ext_hash_valid:
        for id,ext_block in ext_data.items():
            tracks_by_id[id]['userdata'] = ext_block
    else:
        for track in db:
            # make a dict to allow us to find each track by the sha1_hash
            tracks_by_sha[sha1_hash(track.ipod_filename())] = track
        for ext_block in ext_data.values():
            try:
                track = tracks_by_sha[ext_block['sha1_hash']]
            except KeyError:
                # recent gpod uses sha1_hash, older uses md5_hash
                track = tracks_by_sha[ext_block['md5_hash']]                
            track['userdata'] = ext_block