def _shorten_to_bytes_length(text, length): """Truncates a unicode object to the given number of bytes it would take when encoded in the "filesystem encoding". """ assert isinstance(text, str), "This function only works on unicode" raw = encode_filename(text) # maybe there's no need to truncate anything if len(raw) <= length: return text # or maybe there's nothing multi-byte here if len(raw) == len(text): return text[:length] # if we're dealing with utf-8, we can use an efficient algorithm # to deal with character boundaries if _re_utf8.match(_io_encoding): i = length # a UTF-8 intermediate byte starts with the bits 10xxxxxx, # so ord(char) & 0b11000000 = 0b10000000 while i > 0 and (raw[i] & 0xC0) == 0x80: i -= 1 return decode_filename(raw[:i]) # finally, a brute force approach i = length while i > 0: try: return decode_filename(raw[:i]) except UnicodeDecodeError: pass i -= 1 # hmm. we got here? return u""
def _shorten_to_bytes_length(text, length): """Truncates a unicode object to the given number of bytes it would take when encoded in the "filesystem encoding". """ assert isinstance(text, unicode), "This function only works on unicode" raw = encode_filename(text) # maybe there's no need to truncate anything if len(raw) <= length: return text # or maybe there's nothing multi-byte here if len(raw) == len(text): return text[:length] # if we're dealing with utf-8, we can use an efficient algorithm # to deal with character boundaries if _re_utf8.match(_io_encoding): i = length # a UTF-8 intermediate byte starts with the bits 10xxxxxx, # so ord(char) & 0b11000000 = 0b10000000 while i > 0 and (ord(raw[i]) & 0xC0) == 0x80: i -= 1 return decode_filename(raw[:i]) # finally, a brute force approach i = length while i > 0: try: return decode_filename(raw[:i]) except UnicodeDecodeError: pass i -= 1 # hmm. we got here? return u""
def _run_init(self): if self._cmdline_files: files = [] for file in self._cmdline_files: if os.path.isdir(file): self.add_directory(decode_filename(file)) else: files.append(decode_filename(file)) if files: self.add_files(files) del self._cmdline_files
def _run_init(self): if self._args: files = [] for file in self._args: if os.path.isdir(file): self.add_directory(decode_filename(file)) else: files.append(decode_filename(file)) if files: self.add_files(files) del self._args
def _next_filename(self, filename, counters): if counters[filename]: new_filename = "%s (%d)" % (decode_filename(filename), counters[filename]) else: new_filename = filename counters[filename] += 1 return encode_filename(new_filename)
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = encode_filename(os.path.dirname(old_filename)) new_path = encode_filename(os.path.dirname(new_filename)) patterns = encode_filename(config.setting["move_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) try: names = os.listdir(old_path) except os.error: log.error("Error: {} directory not found".format(old_path)) return filtered_names = filter(lambda x: x[0] != '.', names) for pattern in patterns: pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names for old_file in file_names: if pattern_regex.match(old_file): new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = os.path.dirname(old_filename) new_path = os.path.dirname(new_filename) try: names = os.listdir(old_path) except os.error: log.error("Error: {} directory not found".naming_format(old_path)) return filtered_names = [name for name in names if name[0] != "."] for pattern in config.setting["move_additional_files_pattern"].split(): pattern = pattern.strip() if not pattern: continue pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names for old_file in file_names: if pattern_regex.match(old_file): new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def process_directory_listing(self, root, queue, result=None, error=None): try: # Read directory listing if result is not None and error is None: files = [] directories = deque() try: for path in result: path = os.path.join(root, path) if os.path.isdir(path): directories.appendleft(path) else: try: files.append(decode_filename(path)) except UnicodeDecodeError: self.log.warning( "Failed to decode filename: %r", path) continue finally: if files: self.add_files(files) queue.extendleft(directories) finally: # Scan next directory in the queue try: path = queue.popleft() except IndexError: pass else: self.other_queue.put( (partial(os.listdir, path), partial(self.process_directory_listing, path, queue), QtCore.Qt.LowEventPriority))
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = encode_filename(os.path.dirname(old_filename)) new_path = encode_filename(os.path.dirname(new_filename)) patterns = encode_filename( config.setting["move_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) try: names = os.listdir(old_path) except os.error: log.error("Error: {} directory not found".format(old_path)) return filtered_names = filter(lambda x: x[0] != '.', names) for pattern in patterns: pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names for old_file in file_names: if pattern_regex.match(old_file): old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue new_file = os.path.join(new_path, old_file) log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def process_directory_listing(self, root, queue, result=None, error=None): try: # Read directory listing if result is not None and error is None: files = [] directories = deque() try: for path in result: path = os.path.join(root, path) if os.path.isdir(path): directories.appendleft(path) else: try: files.append(decode_filename(path)) except UnicodeDecodeError: self.log.warning("Failed to decode filename: %r", path) continue finally: if files: self.add_files(files) queue.extendleft(directories) finally: # Scan next directory in the queue try: path = queue.popleft() except IndexError: pass else: self.other_queue.put( ( partial(os.listdir, path), partial(self.process_directory_listing, path, queue), QtCore.Qt.LowEventPriority, ) )
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = os.path.dirname(old_filename) new_path = os.path.dirname(new_filename) try: names = set(os.listdir(old_path)) except os.error: log.error("Error: {} directory not found".naming_format(old_path)) return filtered_names = {name for name in names if name[0] != "."} for pattern in config.setting["move_additional_files_pattern"].split(): pattern = pattern.strip() if not pattern: continue pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names for old_file in set(file_names): if pattern_regex.match(old_file): names.discard(old_file) filtered_names.discard(old_file) new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def calculate_replay_gain_for_files(files, format, tagger): """Calculates the replay gain for a list of files in album mode.""" file_list = ['%s' % encode_filename(f.filename) for f in files] if format in REPLAYGAIN_COMMANDS \ and tagger.config.setting[REPLAYGAIN_COMMANDS[format][0]]: command = tagger.config.setting[REPLAYGAIN_COMMANDS[format][0]] options = tagger.config.setting[REPLAYGAIN_COMMANDS[format][1]].split(' ') tagger.log.debug('%s %s %s' % (command, ' '.join(options), decode_filename(' '.join(file_list)))) check_call([command] + options + file_list) else: raise Exception('ReplayGain: Unsupported format %s' % (format))
def _apply_additional_files_moves(self, moves): for old_file_path, new_file_path in moves: # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file_path)): log.debug("File loaded in the tagger, not moving %r", old_file_path) continue log.debug("Moving %r to %r", old_file_path, new_file_path) try: shutil.move(old_file_path, new_file_path) except OSError as why: log.error("Failed to move %r to %r: %s", old_file_path, new_file_path, why)
def generate_moodbar_for_files(files, format, tagger): """Generate the moodfiles for a list of files in album mode.""" file_list = ['%s' % encode_filename(f.filename) for f in files] for mood_file in file_list: new_filename = os.path.join( os.path.dirname(mood_file), '.' + os.path.splitext(os.path.basename(mood_file))[0] + '.mood') # file format to make it compaitble with Amarok and hidden in linux file_list_mood = ['%s' % new_filename] if format in MOODBAR_COMMANDS \ and tagger.config.setting[MOODBAR_COMMANDS[format][0]]: command = tagger.config.setting[MOODBAR_COMMANDS[format][0]] options = tagger.config.setting[MOODBAR_COMMANDS[format][1]].split(' ') # tagger.log.debug('My debug >>> %s' % (file_list_mood)) tagger.log.debug( '%s %s %s %s' % (command, decode_filename(' '.join(file_list)), ' '.join(options), decode_filename(' '.join(file_list_mood)))) check_call([command] + file_list + options + file_list_mood) else: raise Exception('Moodbar: Unsupported format %s' % (format))
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like images, playlists...""" new_path = os.path.dirname(new_filename) old_path = os.path.dirname(old_filename) if new_path == old_path: # skip, same directory, nothing to move return config = get_config() patterns = config.setting["move_additional_files_pattern"] pattern_regexes = set() for pattern in patterns.split(): pattern = pattern.strip() if not pattern: continue pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) match_hidden = pattern.startswith('.') pattern_regexes.add((pattern_regex, match_hidden)) if not pattern_regexes: return moves = set() try: # TODO: use with statement with python 3.6+ for entry in os.scandir(old_path): is_hidden = entry.name.startswith('.') for pattern_regex, match_hidden in pattern_regexes: if is_hidden and not match_hidden: continue if pattern_regex.match(entry.name): new_file_path = os.path.join(new_path, entry.name) moves.add((entry.path, new_file_path)) break # we are done with this file except OSError as why: log.error("Failed to scan %r: %s", old_path, why) return for old_file_path, new_file_path in moves: # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file_path)): log.debug("File loaded in the tagger, not moving %r", old_file_path) continue log.debug("Moving %r to %r", old_file_path, new_file_path) try: shutil.move(old_file_path, new_file_path) except OSError as why: log.error("Failed to move %r to %r: %s", old_file_path, new_file_path, why)
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = encode_filename(os.path.dirname(old_filename)) new_path = encode_filename(os.path.dirname(new_filename)) patterns = encode_filename(config.setting["move_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) for pattern in patterns: # FIXME glob1 is not documented, maybe we need our own implemention? for old_file in glob.glob1(old_path, pattern): new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like images, playlists...""" new_path = os.path.dirname(new_filename) old_path = os.path.dirname(old_filename) if new_path == old_path: # skip, same directory, nothing to move return patterns = config.setting["move_additional_files_pattern"] pattern_regexes = set() for pattern in patterns.split(): pattern = pattern.strip() if not pattern: continue pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) match_hidden = pattern.startswith('.') pattern_regexes.add((pattern_regex, match_hidden)) if not pattern_regexes: return moves = set() try: # TODO: use with statement with python 3.6+ for entry in os.scandir(old_path): is_hidden = entry.name.startswith('.') for pattern_regex, match_hidden in pattern_regexes: if is_hidden and not match_hidden: continue if pattern_regex.match(entry.name): new_file_path = os.path.join(new_path, entry.name) moves.add((entry.path, new_file_path)) break # we are done with this file except OSError as why: log.error("Failed to scan %r: %s", old_path, why) return for old_file_path, new_file_path in moves: # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file_path)): log.debug("File loaded in the tagger, not moving %r", old_file_path) continue log.debug("Moving %r to %r", old_file_path, new_file_path) try: shutil.move(old_file_path, new_file_path) except OSError as why: log.error("Failed to move %r to %r: %s", old_file_path, new_file_path, why)
def _delete_additional_files(self, old_filename): """Delete all other files of type that are not being saved..""" """Retrieve path of saved file""" old_path = encode_filename(os.path.dirname(old_filename)) """Retrieve patterns(types) to be deleted""" patterns = encode_filename( config.setting["delete_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) for pattern in patterns: # FIXME glob1 is not documented, maybe we need our own implementation? for old_file in glob.glob1(old_path, pattern): old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): """Ensures file being saved is not deleted""" log.debug("File loaded in the tagger, not deleting %r", old_file) continue log.debug("Deleting %r", old_file) os.remove(old_file)
def generate_moodbar_for_files(files, format, tagger): """Generate the moodfiles for a list of files in album mode.""" file_list = ['%s' % encode_filename(f.filename) for f in files] for mood_file in file_list: new_filename = os.path.join(os.path.dirname( mood_file), '.' + os.path.splitext(os.path.basename(mood_file))[0] + '.mood') # file format to make it compaitble with Amarok and hidden in linux file_list_mood = ['%s' % new_filename] if format in MOODBAR_COMMANDS \ and tagger.config.setting[MOODBAR_COMMANDS[format][0]]: command = tagger.config.setting[MOODBAR_COMMANDS[format][0]] options = tagger.config.setting[ MOODBAR_COMMANDS[format][1]].split(' ') # tagger.log.debug('My debug >>> %s' % (file_list_mood)) tagger.log.debug( '%s %s %s %s' % (command, decode_filename(' '.join(file_list)), ' '.join(options), decode_filename(' '.join(file_list_mood)))) check_call([command] + file_list + options + file_list_mood) else: raise Exception('Moodbar: Unsupported format %s' % (format))
def _run_init(self): if self._cmdline_files: files = [decode_filename(f) for f in self._cmdline_files] self.add_paths(files) del self._cmdline_files