Пример #1
0
    def __init__(
        self,
        path="library.blb",
        directory="~/Music",
        path_formats=((PF_KEY_DEFAULT, "$artist/$album/$track $title"),),
        art_filename="cover",
        timeout=5.0,
        replacements=None,
        item_fields=ITEM_FIELDS,
        album_fields=ALBUM_FIELDS,
    ):
        if path == ":memory:":
            self.path = path
        else:
            self.path = bytestring_path(normpath(path))
        self.directory = bytestring_path(normpath(directory))
        self.path_formats = path_formats
        self.art_filename = bytestring_path(art_filename)
        self.replacements = replacements

        self.timeout = timeout
        self.conn = sqlite3.connect(self.path, timeout)
        self.conn.row_factory = sqlite3.Row
        # this way we can access our SELECT results like dictionaries

        self._make_table("items", item_fields)
        self._make_table("albums", album_fields)
Пример #2
0
    def __init__(self,
                 path='library.blb',
                 directory='~/Music',
                 path_formats=None,
                 art_filename='cover',
                 item_fields=ITEM_FIELDS,
                 album_fields=ALBUM_FIELDS):
        if path == ':memory:':
            self.path = path
        else:
            self.path = bytestring_path(normpath(path))
        self.directory = bytestring_path(normpath(directory))
        if path_formats is None:
            path_formats = {'default': '$artist/$album/$track $title'}
        elif isinstance(path_formats, basestring):
            path_formats = {'default': path_formats}
        self.path_formats = path_formats
        self.art_filename = bytestring_path(art_filename)

        self.conn = sqlite3.connect(self.path)
        self.conn.row_factory = sqlite3.Row
        # this way we can access our SELECT results like dictionaries

        self._make_table('items', item_fields)
        self._make_table('albums', album_fields)
Пример #3
0
 def __init__(self, path='library.blb',
                    directory='~/Music',
                    path_formats=((PF_KEY_DEFAULT,
                                   '$artist/$album/$track $title'),),
                    art_filename='cover',
                    timeout=5.0,
                    replacements=None,
                    item_fields=ITEM_FIELDS,
                    album_fields=ALBUM_FIELDS):
     if path == ':memory:':
         self.path = path
     else:
         self.path = bytestring_path(normpath(path))
     self.directory = bytestring_path(normpath(directory))
     self.path_formats = path_formats
     self.art_filename = bytestring_path(art_filename)
     self.replacements = replacements
     
     self.timeout = timeout
     self.conn = sqlite3.connect(self.path, timeout)
     self.conn.row_factory = sqlite3.Row
         # this way we can access our SELECT results like dictionaries
     
     self._make_table('items', item_fields)
     self._make_table('albums', album_fields)
Пример #4
0
def move_func(lib, config, opts, args):
    dest = opts.dest
    if dest is not None:
        dest = normpath(dest)
        if not os.path.isdir(dest):
            raise ui.UserError('no such directory: %s' % dest)

    move_items(lib, dest, decargs(args), opts.copy, opts.album)
Пример #5
0
    def read(self, read_path=None):
        """Read the metadata from the associated file. If read_path is
        specified, read metadata from that file instead.
        """
        if read_path is None:
            read_path = self.path
        else:
            read_path = normpath(read_path)
        f = MediaFile(syspath(read_path))

        for key in ITEM_KEYS_META:
            setattr(self, key, getattr(f, key))
        self.path = read_path
Пример #6
0
    def read(self, read_path=None):
        """Read the metadata from the associated file. If read_path is
        specified, read metadata from that file instead.
        """
        if read_path is None:
            read_path = self.path
        else:
            read_path = normpath(read_path)
        f = MediaFile(syspath(read_path))

        for key in ITEM_KEYS_META:
            setattr(self, key, getattr(f, key))
        self.path = read_path
Пример #7
0
 def __init__(self, path='library.blb',
                    directory='~/Music',
                    path_formats=None,
                    art_filename='cover',
                    item_fields=ITEM_FIELDS,
                    album_fields=ALBUM_FIELDS):
     if path == ':memory:':
         self.path = path
     else:
         self.path = bytestring_path(normpath(path))
     self.directory = bytestring_path(normpath(directory))
     if path_formats is None:
         path_formats = {'default': '$artist/$album/$track $title'}
     elif isinstance(path_formats, basestring):
         path_formats = {'default': path_formats}
     self.path_formats = path_formats
     self.art_filename = bytestring_path(art_filename)
     
     self.conn = sqlite3.connect(self.path)
     self.conn.row_factory = sqlite3.Row
         # this way we can access our SELECT results like dictionaries
     
     self._make_table('items', item_fields)
     self._make_table('albums', album_fields)
Пример #8
0
    def read(self, read_path=None):
        """Read the metadata from the associated file. If read_path is
        specified, read metadata from that file instead.
        """
        if read_path is None:
            read_path = self.path
        else:
            read_path = normpath(read_path)
        f = MediaFile(syspath(read_path))

        for key in ITEM_KEYS_META:
            setattr(self, key, getattr(f, key))
        self.path = read_path

        # Database's mtime should now reflect the on-disk value.
        if read_path == self.path:
            self.mtime = self.current_mtime()
Пример #9
0
    def read(self, read_path=None):
        """Read the metadata from the associated file. If read_path is
        specified, read metadata from that file instead.
        """
        if read_path is None:
            read_path = self.path
        else:
            read_path = normpath(read_path)
        f = MediaFile(syspath(read_path))

        for key in ITEM_KEYS_META:
            setattr(self, key, getattr(f, key))
        self.path = read_path

        # Database's mtime should now reflect the on-disk value.
        if read_path == self.path:
            self.mtime = self.current_mtime()
Пример #10
0
    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"]

        # Get values from plugins.
        for key, value in plugins.template_values(item).iteritems():
            mapping[key] = util.sanitize_for_path(value, pathmod, key)

        # Perform substitution.
        funcs = DefaultTemplateFunctions(self, item).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.lower()

        if fragment:
            return subpath
        else:
            basedir = basedir or self.directory
            return normpath(os.path.join(basedir, subpath))
Пример #11
0
    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']

        # Get values from plugins.
        for key, value in plugins.template_values(item).iteritems():
            mapping[key] = util.sanitize_for_path(value, pathmod, key)

        # Perform substitution.
        funcs = DefaultTemplateFunctions(self, item).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.lower()

        if fragment:
            return subpath
        else:
            basedir = basedir or self.directory
            return normpath(os.path.join(basedir, subpath))   
Пример #12
0
 def __init__(self, path):
     # Match the path as a single file.
     self.file_path = normpath(path)
     # As a directory (prefix).
     self.dir_path = os.path.join(self.file_path, "")
Пример #13
0
 def destination(self, item, pathmod=None, in_album=False, fragment=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. 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.
     """
     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:
         return normpath(os.path.join(self.directory, subpath))   
Пример #14
0
 def __init__(self, path):
     self.file_path = normpath(path) # As a file.
     self.dir_path = os.path.join(path, '') # As a directory (prefix).
Пример #15
0
 def __init__(self, path):
     # Match the path as a single file.
     self.file_path = normpath(path)
     # As a directory (prefix).
     self.dir_path = os.path.join(self.file_path, '')
Пример #16
0
def import_files(lib, paths, copy, write, autot, logpath, art, threaded,
                 color, delete, quiet, resume, quiet_fallback, singletons,
                 timid, query, incremental, ignore):
    """Import the files in the given list of paths, tagging each leaf
    directory as an album. If copy, then the files are copied into
    the library folder. If write, then new metadata is written to the
    files themselves. If not autot, then just import the files
    without attempting to tag. If logpath is provided, then untaggable
    albums will be logged there. If art, then attempt to download
    cover art for each album. If threaded, then accelerate autotagging
    imports by running them in multiple threads. If color, then
    ANSI-colorize some terminal output. If delete, then old files are
    deleted when they are copied. If quiet, then the user is
    never prompted for input; instead, the tagger just skips anything
    it is not confident about. resume indicates whether interrupted
    imports can be resumed and is either a boolean or None.
    quiet_fallback should be either ASIS or SKIP and indicates what
    should happen in quiet mode when the recommendation is not strong.
    """
    # Check the user-specified directories.
    for path in paths:
        if not singletons and not os.path.isdir(syspath(path)):
            raise ui.UserError('not a directory: ' + path)
        elif singletons and not os.path.exists(syspath(path)):
            raise ui.UserError('no such file: ' + path)

    # Check parameter consistency.
    if quiet and timid:
        raise ui.UserError("can't be both quiet and timid")

    # Open the log.
    if logpath:
        logpath = normpath(logpath)
        try:
            logfile = open(syspath(logpath), 'a')
        except IOError:
            raise ui.UserError(u"could not open log file for writing: %s" %
                               displayable_path(logpath))
        print >>logfile, 'import started', time.asctime()
    else:
        logfile = None

    # Never ask for input in quiet mode.
    if resume is None and quiet:
        resume = False

    try:
        # Perform the import.
        importer.run_import(
            lib = lib,
            paths = paths,
            resume = resume,
            logfile = logfile,
            color = color,
            quiet = quiet,
            quiet_fallback = quiet_fallback,
            copy = copy,
            write = write,
            art = art,
            delete = delete,
            threaded = threaded,
            autot = autot,
            choose_match_func = choose_match,
            should_resume_func = should_resume,
            singletons = singletons,
            timid = timid,
            choose_item_func = choose_item,
            query = query,
            incremental = incremental,
            ignore = ignore,
            resolve_duplicate_func = resolve_duplicate,
        )
    
    finally:
        # If we were logging, close the file.
        if logfile:
            print >>logfile, ''
            logfile.close()

    # Emit event.
    plugins.send('import', lib=lib, paths=paths)
Пример #17
0
    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))