2 import gtk
, gtk
.glade
, gobject
8 sys
.path
.append(os
.path
.expanduser("~/src/ql/trunk/mutagen"))
11 SUPPORTED_EXTENSIONS
= '.mp3'
22 LOC
[INCOMING
] = conf
.media_dir
23 LOC
[DEVICE
] = conf
.device_dir
26 def list_files(top
, ext
):
27 if isinstance(ext
,list):
28 accept
= lambda e
: e
in ext
30 accept
= lambda e
: e
== ext
31 for r
,ds
,fs
in os
.walk(top
):
33 if accept( os
.path
.splitext(f
)[1] ):
34 yield os
.path
.join(r
,f
)
36 def get_device_tracks():
37 return list_files(LOC
[DEVICE
], SUPPORTED_EXTENSIONS
)
39 def get_incoming_tracks():
40 return list_files(LOC
[INCOMING
], SUPPORTED_EXTENSIONS
)
44 self
.window
= gtk
.Window()
45 self
.window
.set_title('sync')
46 self
.window
.connect('destroy', gtk
.main_quit
)
50 scroll
= gtk
.ScrolledWindow()
51 scroll
.set_policy(gtk
.POLICY_AUTOMATIC
,gtk
.POLICY_AUTOMATIC
)
54 self
.main_list
= gtk
.TreeView()
55 self
.main_list
.set_headers_visible(False)
56 self
.main_list
.set_reorderable(True)
57 self
.main_list
.connect("key-press-event", self
.on_key_press
)
58 self
.main_list
.get_selection().set_mode(gtk
.SELECTION_MULTIPLE
)
60 text_renderer
= gtk
.CellRendererText()
61 column
= gtk
.TreeViewColumn("track", text_renderer
)
62 column
.add_attribute(text_renderer
, "text", TITLE
)
63 column
.add_attribute(text_renderer
, "background", BACKGROUND
)
65 self
.main_list
.append_column( column
)
66 scroll
.add(self
.main_list
)
68 go_button
= gtk
.Button('Go!')
69 go_button
.connect("clicked", self
.do_sync
)
70 vbox
.add_with_properties(go_button
,'expand',False)
74 self
.window
.resize(400,600)
75 self
.window
.show_all()
77 def add_entries(self
, lst
):
78 if self
.main_list
.get_model() is None:
79 self
.main_list
.set_model( gtk
.ListStore(str,str,str,int) )
81 self
.main_list
.get_model().append( i
)
83 def do_sync(self
,*argv
):
84 to_copy
= [row
for row
in self
.main_list
.get_model() if row
[LOCATION
] == INCOMING
]
85 CopyProgress(to_copy
, LOC
[DEVICE
])
87 def on_key_press(self
,widget
,event
,*argv
):
88 if event
.keyval
in (gtk
.keysyms
.Delete
, gtk
.keysyms
.KP_Delete
):
89 self
.delete_selected()
91 def want_file_gone(self
, title
):
92 print "Do you also want to delete track '%s' from incoming directory?" % title
95 def delete_selected(self
):
96 model
,indexes
= self
.main_list
.get_selection().get_selected_rows()
97 iters
= [model
.get_iter(i
) for i
in indexes
]
99 if (model
[i
][LOCATION
] != INCOMING
) or self
.want_file_gone(model
[i
][TITLE
]):
100 os
.remove(model
[i
][FULLPATH
])
104 xml
= gtk
.glade
.XML('sync.glade', root
='copy_progress_dialog')
105 dialog
= xml
.get_widget('copy_progress_dialog')
106 total_progress
= xml
.get_widget('total_progress')
107 file_progress
= xml
.get_widget('file_progress')
112 def __init__(self
, sources
, dest
):
113 if len(sources
) == 0: return
114 self
.total_progress
.set_fraction(0)
115 self
.file_progress
.set_fraction(0)
116 self
.dialog
.show_all()
118 self
.sources
= sources
119 self
.total_sources_count
= len(sources
)
121 self
.source_file
= None
122 self
.dest_file
= None
124 gobject
.idle_add(self
.copy_task
)
127 if self
.source_file
is None:
128 if len(self
.sources
) == 0:
129 self
.dialog
.hide() # done
131 self
.row
= self
.sources
[0]
132 self
.source
= self
.row
[FULLPATH
]
133 self
.sources
= self
.sources
[1:]
134 self
.source_file
= open(self
.source
, 'r')
135 self
.new_path
= os
.path
.join( self
.dest
, os
.path
.basename( self
.source
))
136 self
.dest_file
= open(self
.new_path
, 'w')
137 self
.current_offset
= 0
138 self
.current_size
= os
.stat( self
.source
).st_size
139 self
.file_progress
.set_fraction( 0.0 )
140 chunk_size
= min( self
.buf_len
, self
.current_size
- self
.current_offset
)
141 self
.dest_file
.write( self
.source_file
.read( chunk_size
))
142 self
.current_offset
+= chunk_size
143 self
.file_progress
.set_fraction( float(self
.current_offset
) / self
.current_size
)
144 if self
.current_offset
== self
.current_size
:
145 self
.dest_file
.close()
146 self
.dest_file
= None
147 self
.source_file
.close()
148 self
.source_file
= None
149 os
.remove( self
.source
)
150 self
.total_progress
.set_fraction( 1.0 - (float(len(self
.sources
)) / self
.total_sources_count
))
151 self
.row
[BACKGROUND
] = '#d0d0f0'
152 self
.row
[LOCATION
] = DEVICE
153 self
.row
[FULLPATH
] = self
.new_path
159 tags
= mutagen
.File(t
).tags
161 return "%s (%s)" % (tags
['TIT2'], tags
['TALB'])
165 return os
.path
.basename(t
)
168 LOC
[DEVICE
] = sys
.argv
[1]
169 LOC
[INCOMING
] = sys
.argv
[2]
174 for entry
in [(track_title(t
),'#d0d0f0',t
,DEVICE
) for t
in get_device_tracks()]:
175 app
.add_entries([entry
])
176 for entry
in [(track_title(t
),'#90ff90',t
,INCOMING
) for t
in get_incoming_tracks()]:
177 app
.add_entries([entry
])