finish updating to python 3
This commit is contained in:
parent
d0d8588e5f
commit
503dd069c8
1 changed files with 44 additions and 42 deletions
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
import functools
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
@ -14,18 +14,11 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from builtins import chr
|
|
||||||
from builtins import input
|
from builtins import input
|
||||||
from builtins import map
|
from builtins import map
|
||||||
from builtins import range
|
from builtins import range
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from past.builtins import cmp
|
|
||||||
from past.utils import old_div
|
|
||||||
|
|
||||||
__title__ = "KeyJ's iPod shuffle Database Builder"
|
__title__ = "KeyJ's iPod shuffle Database Builder"
|
||||||
__version__ = "1.0"
|
__version__ = "1.0"
|
||||||
__author__ = "Martin Fiedler"
|
__author__ = "Martin Fiedler"
|
||||||
|
@ -112,7 +105,7 @@ def open_log():
|
||||||
global logfile
|
global logfile
|
||||||
if Options['logging']:
|
if Options['logging']:
|
||||||
try:
|
try:
|
||||||
logfile = file(Options['logfile'], "w")
|
logfile = open(Options['logfile'], "w")
|
||||||
except IOError:
|
except IOError:
|
||||||
logfile = None
|
logfile = None
|
||||||
else:
|
else:
|
||||||
|
@ -166,11 +159,11 @@ def MatchRule(props, rule):
|
||||||
if rule[1] == '~':
|
if rule[1] == '~':
|
||||||
return fnmatch.fnmatchcase(prop.lower(), ref.lower())
|
return fnmatch.fnmatchcase(prop.lower(), ref.lower())
|
||||||
elif rule[1] == '=':
|
elif rule[1] == '=':
|
||||||
return cmp(prop, ref) == 0
|
return prop == ref
|
||||||
elif rule[1] == '>':
|
elif rule[1] == '>':
|
||||||
return cmp(prop, ref) > 0
|
return prop > ref
|
||||||
elif rule[1] == '<':
|
elif rule[1] == '<':
|
||||||
return cmp(prop, ref) < 0
|
return prop < ref
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -193,7 +186,7 @@ def ParseRule(rule):
|
||||||
|
|
||||||
|
|
||||||
def ParseAction(action):
|
def ParseAction(action):
|
||||||
prop, value = list(map(string.strip, action.split('=', 1)))
|
prop, value = list(map(str.strip, action.split('=', 1)))
|
||||||
if not prop in KnownProps:
|
if not prop in KnownProps:
|
||||||
log("WARNING: unknown property `%s'" % prop)
|
log("WARNING: unknown property `%s'" % prop)
|
||||||
return (prop, ParseValue(value))
|
return (prop, ParseValue(value))
|
||||||
|
@ -201,12 +194,12 @@ def ParseAction(action):
|
||||||
|
|
||||||
def ParseRuleLine(line):
|
def ParseRuleLine(line):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not (line) or line[0] == "#":
|
if not line or line[0] == "#":
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
# split line into "ruleset: action"
|
# split line into "ruleset: action"
|
||||||
tmp = line.split(":")
|
tmp = line.split(":")
|
||||||
ruleset = list(map(string.strip, ":".join(tmp[:-1]).split(",")))
|
ruleset = list(map(str.strip, ":".join(tmp[:-1]).split(",")))
|
||||||
actions = dict(list(map(ParseAction, tmp[-1].split(","))))
|
actions = dict(list(map(ParseAction, tmp[-1].split(","))))
|
||||||
if len(ruleset) == 1 and not (ruleset[0]):
|
if len(ruleset) == 1 and not (ruleset[0]):
|
||||||
return ([], actions)
|
return ([], actions)
|
||||||
|
@ -215,7 +208,6 @@ def ParseRuleLine(line):
|
||||||
except OSError: # (ValueError,IndexError,KeyError):
|
except OSError: # (ValueError,IndexError,KeyError):
|
||||||
log("WARNING: rule `%s' is malformed, ignoring" % line)
|
log("WARNING: rule `%s' is malformed, ignoring" % line)
|
||||||
return None
|
return None
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -269,12 +261,12 @@ def write_to_db(filename):
|
||||||
entry = props['reuse'] and (filename in KnownEntries) and KnownEntries[filename]
|
entry = props['reuse'] and (filename in KnownEntries) and KnownEntries[filename]
|
||||||
if not entry:
|
if not entry:
|
||||||
header[29] = props['type']
|
header[29] = props['type']
|
||||||
entry = header.tostring() + \
|
entry = header.tobytes() + \
|
||||||
"".join([c + "\0" for c in filename[:261]]) + \
|
("".join([c + "\0" for c in filename[:261]]) + \
|
||||||
"\0" * (525 - 2 * len(filename))
|
"\0" * (525 - 2 * len(filename))).encode()
|
||||||
|
|
||||||
# write entry, modifying shuffleflag and bookmarkflag at least
|
# write entry, modifying shuffleflag and bookmarkflag at least
|
||||||
iTunesSD.write(entry[:555] + chr(props['shuffle']) + chr(props['bookmark']) + entry[557])
|
iTunesSD.write(entry[:555] + bytes([props['shuffle']]) + bytes([props['bookmark']]) + bytes([entry[557]]))
|
||||||
if props['shuffle']: domains[-1].append(total_count)
|
if props['shuffle']: domains[-1].append(total_count)
|
||||||
total_count += 1
|
total_count += 1
|
||||||
return 1
|
return 1
|
||||||
|
@ -294,7 +286,7 @@ def make_key(s):
|
||||||
|
|
||||||
def key_repr(x):
|
def key_repr(x):
|
||||||
if type(x) == tuple:
|
if type(x) == tuple:
|
||||||
return "%s%d%s" % (x[0], x[1], key_repr(x[2]))
|
return b"%s%d%s" % (x[0], x[1], key_repr(x[2]))
|
||||||
else:
|
else:
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
@ -305,9 +297,14 @@ def cmp_key(a, b):
|
||||||
else:
|
else:
|
||||||
return cmp(key_repr(a), key_repr(b))
|
return cmp(key_repr(a), key_repr(b))
|
||||||
|
|
||||||
|
def cmp(a, b):
|
||||||
|
if a < b: return -1
|
||||||
|
elif a > b: return 1
|
||||||
|
else: return 0
|
||||||
|
|
||||||
|
|
||||||
def file_entry(path, name, prefix=""):
|
def file_entry(path, name, prefix=""):
|
||||||
if not (name) or name[0] == ".": return None
|
if not name or name[0] == ".": return None
|
||||||
fullname = "%s/%s" % (path, name)
|
fullname = "%s/%s" % (path, name)
|
||||||
may_rename = not (fullname.startswith("./iPod_Control")) and Options['rename']
|
may_rename = not (fullname.startswith("./iPod_Control")) and Options['rename']
|
||||||
try:
|
try:
|
||||||
|
@ -315,10 +312,10 @@ def file_entry(path, name, prefix=""):
|
||||||
return None
|
return None
|
||||||
if os.path.isdir(fullname):
|
if os.path.isdir(fullname):
|
||||||
if may_rename: name = rename_safely(path, name)
|
if may_rename: name = rename_safely(path, name)
|
||||||
return (0, make_key(name), prefix + name)
|
return 0, make_key(name), prefix + name
|
||||||
if os.path.splitext(name)[1].lower() in (".mp3", ".m4a", ".m4b", ".m4p", ".aa", ".wav"):
|
if os.path.splitext(name)[1].lower() in (".mp3", ".m4a", ".m4b", ".m4p", ".aa", ".wav"):
|
||||||
if may_rename: name = rename_safely(path, name)
|
if may_rename: name = rename_safely(path, name)
|
||||||
return (1, make_key(name), prefix + name)
|
return 1, make_key(name), prefix + name
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
@ -362,7 +359,7 @@ def browse(path, interactive):
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
files.sort(cmp_key)
|
files.sort(key = functools.cmp_to_key(cmp_key))
|
||||||
count = len([None for x in files if x[0]])
|
count = len([None for x in files if x[0]])
|
||||||
if count: domains.append([])
|
if count: domains.append([])
|
||||||
|
|
||||||
|
@ -385,7 +382,7 @@ def browse(path, interactive):
|
||||||
|
|
||||||
def stringval(i):
|
def stringval(i):
|
||||||
if i < 0: i += 0x1000000
|
if i < 0: i += 0x1000000
|
||||||
return "%c%c%c" % (i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF)
|
return b"%c%c%c" % (i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
def listval(i):
|
def listval(i):
|
||||||
|
@ -399,20 +396,21 @@ def make_playback_state(volume=None):
|
||||||
log("Setting playback state ...", False)
|
log("Setting playback state ...", False)
|
||||||
PState = []
|
PState = []
|
||||||
try:
|
try:
|
||||||
f = file("iPod_Control/iTunes/iTunesPState", "rb")
|
f = open("iPod_Control/iTunes/iTunesPState", "rb")
|
||||||
a = array.array('B')
|
a = array.array('B')
|
||||||
a.fromstring(f.read())
|
a.frombytes(f.read())
|
||||||
PState = a.tolist()
|
PState = a.tolist()
|
||||||
f.close()
|
f.close()
|
||||||
except IOError as EOFError:
|
except IOError:
|
||||||
del PState[:]
|
del PState[:]
|
||||||
if len(PState) != 21:
|
#if len(PState) != 21:
|
||||||
PState = listval(29) + [0] * 15 + listval(1) # volume 29, FW ver 1.0
|
# print("catstare")
|
||||||
|
# PState = listval(29) + [0] * 15 + listval(1) # volume 29, FW ver 1.0
|
||||||
PState[3:15] = [0] * 6 + [1] + [0] * 5 # track 0, shuffle mode, start of track
|
PState[3:15] = [0] * 6 + [1] + [0] * 5 # track 0, shuffle mode, start of track
|
||||||
if volume is not None:
|
if volume is not None:
|
||||||
PState[:3] = listval(volume)
|
PState[:3] = listval(volume)
|
||||||
try:
|
try:
|
||||||
f = file("iPod_Control/iTunes/iTunesPState", "wb")
|
f = open("iPod_Control/iTunes/iTunesPState", "wb")
|
||||||
array.array('B', PState).tofile(f)
|
array.array('B', PState).tofile(f)
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -425,8 +423,9 @@ def make_playback_state(volume=None):
|
||||||
def make_stats(count):
|
def make_stats(count):
|
||||||
log("Creating statistics file ...", False)
|
log("Creating statistics file ...", False)
|
||||||
try:
|
try:
|
||||||
file("iPod_Control/iTunes/iTunesStats", "wb").write( \
|
file = open("iPod_Control/iTunes/iTunesStats", "wb")
|
||||||
stringval(count) + "\0" * 3 + (stringval(18) + "\xff" * 3 + "\0" * 12) * count)
|
file.write(stringval(count) + b"\0" * 3 + (stringval(18) + b"\xff" * 3 + b"\0" * 12) * count)
|
||||||
|
file.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
log("FAILED.")
|
log("FAILED.")
|
||||||
return 0
|
return 0
|
||||||
|
@ -453,11 +452,11 @@ def smart_shuffle():
|
||||||
metric = [
|
metric = [
|
||||||
min([slice_count] + [min(abs(s - u), abs(s - u + slice_count), abs(s - u - slice_count)) for u in used])
|
min([slice_count] + [min(abs(s - u), abs(s - u + slice_count), abs(s - u - slice_count)) for u in used])
|
||||||
for s in range(slice_count)]
|
for s in range(slice_count)]
|
||||||
thresh = old_div((max(metric) + 1), 2)
|
thresh = (max(metric) + 1) // 2
|
||||||
farthest = [s for s in range(slice_count) if metric[s] >= thresh]
|
farthest = [s for s in range(slice_count) if metric[s] >= thresh]
|
||||||
|
|
||||||
# find emptiest slices
|
# find emptiest slices
|
||||||
thresh = old_div((min(slice_fill) + max(slice_fill) + 1), 2)
|
thresh = (min(slice_fill) + max(slice_fill) + 1) // 2
|
||||||
emptiest = [s for s in range(slice_count) if slice_fill[s] <= thresh if (s in farthest)]
|
emptiest = [s for s in range(slice_count) if slice_fill[s] <= thresh if (s in farthest)]
|
||||||
|
|
||||||
# choose one of the remaining candidates and add the track to the chosen slice
|
# choose one of the remaining candidates and add the track to the chosen slice
|
||||||
|
@ -488,7 +487,8 @@ def make_shuffle(count):
|
||||||
seq = list(range(count))
|
seq = list(range(count))
|
||||||
random.shuffle(seq)
|
random.shuffle(seq)
|
||||||
try:
|
try:
|
||||||
file("iPod_Control/iTunes/iTunesShuffle", "wb").write("".join(map(stringval, seq)))
|
with open("iPod_Control/iTunes/iTunesShuffle", "wb") as file:
|
||||||
|
file.write(b"".join(map(stringval, seq)))
|
||||||
except IOError:
|
except IOError:
|
||||||
log("FAILED.")
|
log("FAILED.")
|
||||||
return 0
|
return 0
|
||||||
|
@ -505,7 +505,7 @@ def main(dirs):
|
||||||
log()
|
log()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = file("rebuild_db.rules", "r")
|
f = open("rebuild_db.rules", "r")
|
||||||
Rules += [_f for _f in map(ParseRuleLine, f.read().split("\n")) if _f]
|
Rules += [_f for _f in map(ParseRuleLine, f.read().split("\n")) if _f]
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -521,13 +521,13 @@ Please make sure that:
|
||||||
header = array.array('B')
|
header = array.array('B')
|
||||||
iTunesSD = None
|
iTunesSD = None
|
||||||
try:
|
try:
|
||||||
iTunesSD = file("iPod_Control/iTunes/iTunesSD", "rb")
|
iTunesSD = open("iPod_Control/iTunes/iTunesSD", "rb")
|
||||||
header.fromfile(iTunesSD, 51)
|
header.fromfile(iTunesSD, 51)
|
||||||
if Options['reuse']:
|
if Options['reuse']:
|
||||||
iTunesSD.seek(18)
|
iTunesSD.seek(18)
|
||||||
entry = iTunesSD.read(558)
|
entry = iTunesSD.read(558)
|
||||||
while len(entry) == 558:
|
while len(entry) == 558:
|
||||||
filename = entry[33::2].split("\0", 1)[0]
|
filename = entry[33::2].split(b"\0", 1)[0]
|
||||||
KnownEntries[filename] = entry
|
KnownEntries[filename] = entry
|
||||||
entry = iTunesSD.read(558)
|
entry = iTunesSD.read(558)
|
||||||
except (IOError, EOFError):
|
except (IOError, EOFError):
|
||||||
|
@ -551,7 +551,7 @@ Please make sure that:
|
||||||
|
|
||||||
log()
|
log()
|
||||||
try:
|
try:
|
||||||
iTunesSD = file("iPod_Control/iTunes/iTunesSD", "wb")
|
iTunesSD = open("iPod_Control/iTunes/iTunesSD", "wb")
|
||||||
header[:18].tofile(iTunesSD)
|
header[:18].tofile(iTunesSD)
|
||||||
except IOError:
|
except IOError:
|
||||||
log("""ERROR: Cannot write to the iPod database file (iTunesSD)!
|
log("""ERROR: Cannot write to the iPod database file (iTunesSD)!
|
||||||
|
@ -572,7 +572,7 @@ Please make sure that:
|
||||||
log()
|
log()
|
||||||
log("Fixing iTunesSD header.")
|
log("Fixing iTunesSD header.")
|
||||||
iTunesSD.seek(0)
|
iTunesSD.seek(0)
|
||||||
iTunesSD.write("\0%c%c" % (total_count >> 8, total_count & 0xFF))
|
iTunesSD.write(b"\0%c%c" % (total_count >> 8, total_count & 0xFF))
|
||||||
iTunesSD.close()
|
iTunesSD.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
log("ERROR: Some strange errors occured while writing iTunesSD.")
|
log("ERROR: Some strange errors occured while writing iTunesSD.")
|
||||||
|
@ -625,6 +625,8 @@ def parse_options():
|
||||||
"logfile=", "rename"])
|
"logfile=", "rename"])
|
||||||
except getopt.GetoptError as message:
|
except getopt.GetoptError as message:
|
||||||
opterr(message)
|
opterr(message)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
for opt, arg in opts:
|
for opt, arg in opts:
|
||||||
if opt in ("-h", "--help"):
|
if opt in ("-h", "--help"):
|
||||||
help()
|
help()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue