def test_component_sanitize_uses_khz_samplerate(self): val = util.sanitize_for_path(12345, posixpath, 'samplerate') self.assertEqual(val, u'12kHz')
def test_component_sanitize_pads_with_zero(self): name = util.sanitize_for_path(1, posixpath, 'track') self.assertTrue(name.startswith('0'))
def test_component_sanitize_uses_kbps_bitrate(self): val = util.sanitize_for_path(12345, posixpath, 'bitrate') self.assertEqual(val, u'12kbps')
def destination(self, item, pathmod=None, in_album=False, fragment=False, basedir=None): """Returns the path in the library directory designated for item item (i.e., where the file ought to be). in_album forces the item to be treated as part of an album. fragment makes this method return just the path fragment underneath the root library directory; the path is also returned as Unicode instead of encoded as a bytestring. basedir can override the library's base directory for the destination. """ pathmod = pathmod or os.path # Use a path format based on the album type, if available. if not item.album_id and not in_album: # Singleton track. Never use the "album" formats. if 'singleton' in self.path_formats: path_format = self.path_formats['singleton'] else: path_format = self.path_formats['default'] elif item.albumtype and item.albumtype in self.path_formats: path_format = self.path_formats[item.albumtype] elif item.comp and 'comp' in self.path_formats: path_format = self.path_formats['comp'] else: path_format = self.path_formats['default'] subpath_tmpl = Template(path_format) # Get the item's Album if it has one. album = self.get_album(item) # Build the mapping for substitution in the path template, # beginning with the values from the database. mapping = {} for key in ITEM_KEYS_META: # Get the values from either the item or its album. if key in ALBUM_KEYS_ITEM and album is not None: # From album. value = getattr(album, key) else: # From Item. value = getattr(item, key) mapping[key] = util.sanitize_for_path(value, pathmod, key) # Use the album artist if the track artist is not set and # vice-versa. if not mapping['artist']: mapping['artist'] = mapping['albumartist'] if not mapping['albumartist']: mapping['albumartist'] = mapping['artist'] # Perform substitution. subpath = subpath_tmpl.substitute(mapping) # Encode for the filesystem, dropping unencodable characters. if isinstance(subpath, unicode) and not fragment: encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() subpath = subpath.encode(encoding, 'replace') # Truncate components and remove forbidden characters. subpath = util.sanitize_path(subpath) # Preserve extension. _, extension = pathmod.splitext(item.path) subpath += extension if fragment: return subpath else: basedir = basedir or self.directory return normpath(os.path.join(basedir, subpath))
def test_component_sanitize_replaces_separators(self): name = posixpath.join('a', 'b') newname = util.sanitize_for_path(name, posixpath) self.assertNotEqual(name, newname)
def destination(self, item, pathmod=None, in_album=False, fragment=False, basedir=None): """Returns the path in the library directory designated for item item (i.e., where the file ought to be). in_album forces the item to be treated as part of an album. fragment makes this method return just the path fragment underneath the root library directory; the path is also returned as Unicode instead of encoded as a bytestring. basedir can override the library's base directory for the destination. """ pathmod = pathmod or os.path # Use a path format based on a query, falling back on the # default. for query, path_format in self.path_formats: if query == PF_KEY_DEFAULT: continue query = AndQuery.from_string(query) if in_album: # If we're treating this item as a member of the item, # hack the query so that singleton queries always # observe the item to be non-singleton. for i, subquery in enumerate(query): if isinstance(subquery, SingletonQuery): query[i] = FalseQuery() if subquery.sense \ else TrueQuery() if query.match(item): # The query matches the item! Use the corresponding path # format. break else: # No query matched; fall back to default. for query, path_format in self.path_formats: if query == PF_KEY_DEFAULT: break else: assert False, "no default path format" subpath_tmpl = Template(path_format) # Get the item's Album if it has one. album = self.get_album(item) # Build the mapping for substitution in the path template, # beginning with the values from the database. mapping = {} for key in ITEM_KEYS_META: # Get the values from either the item or its album. if key in ALBUM_KEYS_ITEM and album is not None: # From album. value = getattr(album, key) else: # From Item. value = getattr(item, key) mapping[key] = util.sanitize_for_path(value, pathmod, key) # Use the album artist if the track artist is not set and # vice-versa. if not mapping['artist']: mapping['artist'] = mapping['albumartist'] if not mapping['albumartist']: mapping['albumartist'] = mapping['artist'] # Perform substitution. mapping.update(plugins.template_values(item)) funcs = dict(TEMPLATE_FUNCTIONS) funcs.update(plugins.template_funcs()) subpath = subpath_tmpl.substitute(mapping, funcs) # Encode for the filesystem, dropping unencodable characters. if isinstance(subpath, unicode) and not fragment: encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() subpath = subpath.encode(encoding, 'replace') # Truncate components and remove forbidden characters. subpath = util.sanitize_path(subpath, pathmod, self.replacements) # Preserve extension. _, extension = pathmod.splitext(item.path) subpath += extension if fragment: return subpath else: basedir = basedir or self.directory return normpath(os.path.join(basedir, subpath))
def destination(self, item, pathmod=None, in_album=False): """Returns the path in the library directory designated for item item (i.e., where the file ought to be). in_album forces the item to be treated as part of an album. """ pathmod = pathmod or os.path # Use a path format based on the album type, if available. if not item.album_id and not in_album: # Singleton track. Never use the "album" formats. if 'singleton' in self.path_formats: path_format = self.path_formats['singleton'] else: path_format = self.path_formats['default'] elif item.albumtype and item.albumtype in self.path_formats: path_format = self.path_formats[item.albumtype] elif item.comp and 'comp' in self.path_formats: path_format = self.path_formats['comp'] else: path_format = self.path_formats['default'] subpath_tmpl = Template(path_format) # Get the item's Album if it has one. album = self.get_album(item) # Build the mapping for substitution in the path template, # beginning with the values from the database. mapping = {} for key in ITEM_KEYS_META: # Get the values from either the item or its album. if key in ALBUM_KEYS_ITEM and album is not None: # From album. value = getattr(album, key) else: # From Item. value = getattr(item, key) mapping[key] = util.sanitize_for_path(value, pathmod, key) # Use the album artist if the track artist is not set and # vice-versa. if not mapping['artist']: mapping['artist'] = mapping['albumartist'] if not mapping['albumartist']: mapping['albumartist'] = mapping['artist'] # Perform substitution. subpath = subpath_tmpl.substitute(mapping) # Encode for the filesystem, dropping unencodable characters. if isinstance(subpath, unicode): encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() subpath = subpath.encode(encoding, 'replace') # Truncate components and remove forbidden characters. subpath = util.sanitize_path(subpath) # Preserve extension. _, extension = pathmod.splitext(item.path) subpath += extension return normpath(os.path.join(self.directory, subpath))