I recently got myself a Sansa Clip+. Not only does it support FLAC and ReplayGain out of the box, the thing is tiny and can take a 16GB microSD card. Only problem: no support in everyone's favorite music player for syncing to non-iPod devices! So, I fixed that.
Find enclosed one (1) (uno) script, quickly hacked together, to sync files from any one playlist in foobar2000 to a device. This script requires [a href=\'index.php?showtopic=39946\']foo_comserver2[/a] to be installed, along with Python itself. If the Python example that comes with foo_comserver2 works, so will this script.
VERY IMPORTANT: Before you use this, you will need to change three things in the script to suit your setup!
1. playlist_to_sync: add the full name of the playlist or autoplaylist you wish to sync here, between the quotes.
2. base_dir: replace 'E:\\Music\\FLAC\\' with the full path of where your files are located. For example, my files are in E:\Music\FLAC\%album artist%\%album%\etc. Be sure to double-up your backslashes here, otherwise this will not work.
3. target_dir: again, replace 'G:\\MUSIC\\' with where you want your files to wind up. My Sansa's microSD slot shows up at G:\, hence what I have filled in here.
Once run, the script polls foobar2000 for the full path of each track on the named playlist. It then steps through the list of paths, to see if a matching file exists on the target; if it does, and it's the same file, it continues gracefully. Otherwise, it copies the file to the target.
Note: this script does not have a GUI, because I simply don't care enough to make one right now. Maybe later. If you want to, feel free. Run this script in a command prompt. (ie. 'python sync.py' or similar)
I assign all rights to this little hackjob to the community that's made listening to music on Windows so much more fun. Keep up the good work, everyone.
# playlist-to-device sync script for foobar2000
# tested on Windows XP SP3, Python 2.6.2, foobar2000 1.0, and foo_comserver2 0.7a6
# progress bar code shamelessly cribbed from [url=http://stackoverflow.com/questions/274493/how-to-copy-a-file-in-python-with-a-progress-bar]http://stackoverflow.com/questions/274493/...-a-progress-bar[/url]
# questions? kerobaros@gmail.com
import win32com.client
import os, filecmp, shutil, sys
# --- CONFIGURATION STARTS HERE ---
playlist_to_sync = 'Rating > 3'
base_dir = 'E:\\Music\\FLAC\\'
target_dir = 'G:\\MUSIC\\'
# --- CONFIGURATION ENDS HERE ---
class ProgressBar:
"""From [url=http://code.activestate.com/recipes/168639/"""]http://code.activestate.com/recipes/168639...ot;""[/url]
def __init__(self, minValue = 0, maxValue = 10, totalWidth=12):
self.progBar = "[]" # This holds the progress bar string
self.min = minValue
self.max = maxValue
self.span = maxValue - minValue
self.width = totalWidth
self.amount = 0 # When amount == max, we are 100% done
self.updateAmount(0) # Build progress bar string
def updateAmount(self, newAmount = 0):
if newAmount < self.min: newAmount = self.min
if newAmount > self.max: newAmount = self.max
self.amount = newAmount
# Figure out the new percent done, round to an integer
diffFromMin = float(self.amount - self.min)
percentDone = (diffFromMin / float(self.span)) * 100.0
percentDone = round(percentDone)
percentDone = int(percentDone)
# Figure out how many hash bars the percentage should be
allFull = self.width - 2
numHashes = (percentDone / 100.0) * allFull
numHashes = int(round(numHashes))
# build a progress bar with hashes and spaces
self.progBar = "[" + '#'*numHashes + ' '*(allFull-numHashes) + "]"
# figure out where to put the percentage, roughly centered
percentPlace = (len(self.progBar) / 2) - len(str(percentDone))
percentString = str(percentDone) + "%"
# slice the percentage into the bar
self.progBar = (self.progBar[0:percentPlace] + percentString
+ self.progBar[percentPlace+len(percentString):])
def __str__(self):
return str(self.progBar)
def copy_with_prog(src_file, dest_file, overwrite = False, block_size = 512):
if not overwrite:
if os.path.isfile(dest_file):
raise IOError("File exists, not overwriting")
# Open src and dest files, get src file size
src = open(src_file, "rb")
dest = open(dest_file, "wb")
src_size = os.stat(src_file).st_size
# Set progress bar
prgb = ProgressBar(totalWidth = 79, maxValue = src_size)
# Start copying file
cur_block_pos = 0 # a running total of current position
while True:
cur_block = src.read(block_size)
# Update progress bar
prgb.updateAmount(cur_block_pos)
cur_block_pos += block_size
sys.stdout.write(
'\r%s\r' % str(prgb)
)
# If it's the end of file
if not cur_block:
# ..write new line to prevent messing up terminal
sys.stderr.write('\n')
break
else:
# ..if not, write the block and continue
dest.write(cur_block)
#end while
# Close files
src.close()
dest.close()
# Check output file is same size as input one!
dest_size = os.stat(dest_file).st_size
if dest_size != src_size:
raise IOError(
"New file-size does not match original (src: %s, dest: %s)" % (
src_size, dest_size)
)
def get_tracks():
try:
ProgID = "Foobar2000.Application.0.7"
fb2k = win32com.client.Dispatch(ProgID)
except: pass
pls = fb2k.Playlists
tracks = []
for playlist in pls:
if playlist.Name == playlist_to_sync:
for track in playlist.GetTracks(): tracks.append(track.FormatTitle("%path%"))
return tracks
def from_base_to_target(old_name):
return old_name.replace(base_dir, target_dir).encode('latin-1')
def copy_track(base_name, target_name):
if os.path.exists(base_name):
if os.path.exists(target_name):
if filecmp.cmp(base_name, target_name): print '%s skipped, already synced.' % (target_name.replace(target_dir,''))
else:
os.remove(target_name)
#shutil.copy2(base_name, target_name)
copy_with_prog(base_name, target_name)
print '%s out-of-date, resynced.' % (target_name.replace(target_dir,''))
else:
if not os.path.exists(os.path.dirname(target_name)): os.makedirs(os.path.dirname(target_name))
#shutil.copy2(base_name, target_name)
copy_with_prog(base_name, target_name)
print '%s synced.' % (target_name.replace(target_dir,''))
def main():
tracks = get_tracks()
for track in tracks:
copy_track(track, from_base_to_target(track))
main()