def _window_response(self, window, response): if response == Gtk.ResponseType.CLOSE: self.last_tab = self.prefsnotebook.get_current_page() #XXX: These two are probably never triggered if self.config.show_lyrics and self.config.lyrics_location != consts.LYRICS_LOCATION_HOME: if not os.path.isdir(misc.file_from_utf8(self.config.musicdir[self.config.profile_num])): ui.show_msg(self.window, _("To save lyrics to the music file's directory, you must specify a valid music directory."), _("Music Dir Verification"), 'musicdirVerificationError', Gtk.ButtonsType.CLOSE) # Set music_dir entry focused: self.prefsnotebook.set_current_page(0) self.direntry.grab_focus() return if self.config.show_covers and self.config.art_location != consts.ART_LOCATION_HOMECOVERS: if not os.path.isdir(misc.file_from_utf8(self.config.musicdir[self.config.profile_num])): ui.show_msg(self.window, _("To save artwork to the music file's directory, you must specify a valid music directory."), _("Music Dir Verification"), 'musicdirVerificationError', Gtk.ButtonsType.CLOSE) # Set music_dir entry focused: self.prefsnotebook.set_current_page(0) self.direntry.grab_focus() return if not self.using_mpd_env_vars: if self.prev_host != self.config.host[self.config.profile_num] or self.prev_port != self.config.port[self.config.profile_num] or self.prev_password != self.config.password[self.config.profile_num]: # Try to connect if mpd connection info has been updated: ui.change_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) self.reconnect() self.settings_save() self.populate_profiles_for_menu() ui.change_cursor(None) window.destroy()
def target_lyrics_filename(self, artist, title, song_dir, force_location=None): """get the filename of the lyrics of a song""" cfg = self.config # alias for easier access # FIXME Why did we have this condition here: if self.conn: lyrics_loc = force_location if force_location else cfg.lyrics_location if song_dir is not None: song_dir.replace('%', '%%') music_dir = cfg.musicdir[cfg.profile_num].replace('%', '%%') pattern1 = "%s-%s.txt" pattern2 = "%s - %s.txt" # Note: *_ALT searching is for compatibility with other mpd clients # (like ncmpcpp): file_map = { consts.LYRICS_LOCATION_HOME: ("~/.lyrics", pattern1), consts.LYRICS_LOCATION_PATH: (music_dir, song_dir, pattern1), consts.LYRICS_LOCATION_HOME_ALT: ("~/.lyrics", pattern2), consts.LYRICS_LOCATION_PATH_ALT: (music_dir, song_dir, pattern2), } file_path = os.path.join(*file_map[lyrics_loc]) file_path = os.path.expanduser(file_path) % (artist, title) return misc.file_from_utf8( misc.file_exists_insensitive(file_path))
def artwork_get_misc_img_in_path(self, songdir): path = os.path.join(self.config.musicdir[self.config.profile_num], songdir) dir = misc.file_from_utf8(path) if os.path.exists(dir): for name in consts.ART_LOCATIONS_MISC: filename = os.path.join(dir, name) if os.path.exists(filename): return filename return False
def _update_song(self, songinfo): artistlabel = self.info_labels['artist'] tracklabel = self.info_labels['track'] albumlabel = self.info_labels['album'] filelabel = self.info_labels['file'] for name in ['title', 'date', 'genre']: label = self.info_labels[name] label.set_text(songinfo.get(name, '')) tracklabel.set_text(str(songinfo.track)) artistlabel.set_text(misc.escape_html(songinfo.artist)) albumlabel.set_text(misc.escape_html(songinfo.album)) path = misc.file_from_utf8(os.path.join( self.config.musicdir[self.config.profile_num], songinfo.file)) if os.path.exists(path): filelabel.set_text(path) self._editlabel.show() else: filelabel.set_text(songinfo.file) self._editlabel.hide()
def on_dnd(self, treeview, drag_context, x, y, selection, _info, timestamp): drop_info = treeview.get_dest_row_at_pos(x, y) if selection.data is not None: if not os.path.isdir(misc.file_from_utf8( self.config.musicdir[self.config.profile_num])): return # DND from outside sonata: uri = selection.data.strip() path = urllib.request.url2pathname(uri) paths = path.rsplit('\n') mpdpaths = [] # Strip off paranthesis so that we can DND entire music dir # if we wish. musicdir = self.config.musicdir[self.config.profile_num][:-1] for i, path in enumerate(paths): paths[i] = path.rstrip('\r') if paths[i].startswith('file://'): paths[i] = paths[i][7:] elif paths[i].startswith('file:'): paths[i] = paths[i][5:] if paths[i].startswith(musicdir): paths[i] = paths[i][len(musicdir):] if len(paths[i]) == 0: paths[i] = "/" listallinfo = self.mpd.listallinfo(paths[i]) for item in listallinfo: if 'file' in item: mpdpaths.append(item['file']) # Add local file, available in mpd 0.14. This currently # work because python-mpd does not support unix socket # paths, won't which is needed for authentication for # local files. It's also therefore untested. if os.path.isdir(misc.file_from_utf8(paths[i])): filenames = misc.get_files_recursively(paths[i]) else: filenames = [paths[i]] for filename in filenames: if os.path.exists(misc.file_from_utf8(filename)): mpdpaths.append("file://" + urllib.parse.quote(filename)) if len(mpdpaths) > 0: # Items found, add to list at drop position: if drop_info: destpath, position = drop_info if position in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE): songid = destpath[0] else: songid = destpath[0] + 1 else: songid = len(self.currentdata) for mpdpath in mpdpaths: self.mpd.addid(mpdpath, songid) self.iterate_now() return # Otherwise, it's a DND just within the current playlist model = treeview.get_model() _foobar, selected = self.current_selection.get_selected_rows() # calculate all this now before we start moving stuff drag_sources = [] for path in selected: index = path[0] i = model.get_iter(path) songid = self.current_get_songid(i, model) text = model.get_value(i, 1) drag_sources.append([index, i, songid, text]) # Keep track of the moved iters so we can select them afterwards moved_iters = [] # We will manipulate self.current_songs and model to prevent # the entire playlist from refreshing offset = 0 self.mpd.command_list_ok_begin() for source in drag_sources: index, i, songid, text = source if drop_info: destpath, position = drop_info dest = destpath[0] + offset if dest < index: offset = offset + 1 if position in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE): self.current_songs.insert(dest, self.current_songs[index]) if dest < index + 1: self.current_songs.pop(index + 1) self.mpd.moveid(songid, dest) else: self.current_songs.pop(index) self.mpd.moveid(songid, dest - 1) model.insert(dest, model[index]) moved_iters += [model.get_iter((dest,))] model.remove(i) else: self.current_songs.insert(dest + 1, self.current_songs[index]) if dest < index: self.current_songs.pop(index + 1) self.mpd.moveid(songid, dest + 1) else: self.current_songs.pop(index) self.mpd.moveid(songid, dest) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1,))] model.remove(i) else: #dest = int(self.status['playlistlength']) - 1 dest = len(self.currentdata) - 1 self.mpd.moveid(songid, dest) self.current_songs.insert(dest + 1, self.current_songs[index]) self.current_songs.pop(index) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1,))] model.remove(i) # now fixup for source in drag_sources: if dest < index: # we moved it back, so all indexes inbetween increased by 1 if dest < source[0] < index: source[0] += 1 else: # we moved it ahead, so all indexes inbetween # decreased by 1 if index < source[0] < dest: source[0] -= 1 self.mpd.command_list_end() # we are manipulating the model manually for speed, so... self.current_update_skip = True if drag_context.action == Gdk.DragAction.MOVE: drag_context.finish(True, True, timestamp) self.header_hide_all_indicators(self.current, False) self.iterate_now() GLib.idle_add(self.dnd_retain_selection, treeview.get_selection(), moved_iters)
def on_tags_edit(self, files, temp_mpdpaths, music_dir): """Display the editing dialog""" # Try loading module global tagpy if tagpy is None: try: import tagpy except ImportError: ui.show_msg(self.window, _("Taglib and/or tagpy not found, tag editing support disabled."), _("Edit Tags"), 'editTagsError', Gtk.ButtonsType.CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # Set default tag encoding to utf8.. fixes some reported bugs. import tagpy.id3v2 as id3v2 id3v2.FrameFactory.instance().setDefaultTextEncoding(tagpy.StringType.UTF8) # Make sure tagpy is at least 0.91 if hasattr(tagpy.Tag.title, '__call__'): ui.show_msg(self.window, _("Tagpy version < 0.91. Please upgrade to a newer version, tag editing support disabled."), _("Edit Tags"), 'editTagsError', Gtk.ButtonsType.CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return if not os.path.isdir(misc.file_from_utf8(music_dir)): ui.show_msg(self.window, _("The path %s does not exist. Please specify a valid music directory in preferences.") % music_dir, _("Edit Tags"), 'editTagsError', Gtk.ButtonsType.CLOSE, response_cb=ui.dialog_destroy) ui.change_cursor(None) return # XXX file list was created here if len(files) == 0: ui.change_cursor(None) return # Initialize: self.tagnum = -1 self.tags = [{ 'title': '', 'artist': '', 'album': '', 'year': '', 'track': '', 'genre': '', 'comment': '', 'title-changed': False, 'artist-changed': False, 'album-changed': False, 'year-changed': False, 'track-changed': False, 'genre-changed': False, 'comment-changed': False, 'fullpath': misc.file_from_utf8(filename), 'mpdpath': path,} for filename, path in zip(files, temp_mpdpaths)] if not os.path.exists(self.tags[0]['fullpath']): ui.change_cursor(None) ui.show_msg(self.window, _("File '%s' not found. Please specify a valid music directory in preferences.") % self.tags[0]['fullpath'], _("Edit Tags"), 'editTagsError', Gtk.ButtonsType.CLOSE, response_cb=ui.dialog_destroy) return if not self.tags_next_tag(): ui.change_cursor(None) ui.show_msg(self.window, _("No music files with editable tags found."), _("Edit Tags"), 'editTagsError', Gtk.ButtonsType.CLOSE, response_cb=ui.dialog_destroy) return if not self.edit_window: self._init_edit_window() saveall_button = self.builder.get_object('tags_saveall_button') if len(files) > 1: # Only show save all button if more than one song being edited. saveall_button.show() saveall_button.set_property("visible", True) else: saveall_button.hide() saveall_button.set_property("visible", False) self.tags_win_update() self.edit_window.show_all() SAVE_ALL = -12 done = False while not done: # Next file: self.tags_win_update() response = self.edit_window.run() if response == SAVE_ALL: self.save_tag() while self.tags_next_tag(): self.tags_win_update() self.save_tag() done = True elif response == Gtk.ResponseType.ACCEPT: self.save_tag() done = not self.tags_next_tag() if done: # To ensure we update the last file in tags_mpd_update self.tagnum = self.tagnum + 1 elif response == Gtk.ResponseType.REJECT: done = True tag_paths = (tag['mpdpath'] for tag in self.tags[:self.tagnum]) GLib.idle_add(self.tags_mpd_update, tag_paths) self.tags_set_use_mpdpath(self.use_mpdpaths) self.tags = None ui.change_cursor(None) self.edit_window.hide()