Beispiel #1
0
def _store_annotations(audiofile, track, all_md=False):
    """Searches for metadata related to the audio-file (v 1.0; for now only ID3 in MP3): type <id3> annotation [tagname];
    Searches for text-files with the same base-name whithin the folder (any [ext]ension): type <txt> annotation [ext];
    Stores these annotation values in the track_annotation DB table
    
    @param audiofile: the file (should be previously verified as an actual audio file)
    @param track: previously stored track record in the database, represented by a gordon.db.model.Track class (SQL Alchemy)
    @param all_md: use True to extract all tags from the audio-file (defaults to False) 
    
    returns number of annotations (0 to *) stored"""
    
    annots = 0
    
    #chek if file is mp3. if so:
    if all_md:
        if id3.isValidMP3(audiofile):
            #extract all ID3 tags, store each tag value as an annotation type id3.[tagname]
            for tag in id3.getAllTags(audiofile, skipTrackFields=True): # this skips the 4 basic tags already in track
                track.annotations.append(Annotation(name=unicode(tag[0]), value=tag[1])) #todo: value=unicode(tag[1])
                annots += 1
    
        #future todo: apply tagpy or other method to extract more metadata formats
    
    if annots == 0: log.debug('    No ID3 metadata found.')
    
    # check text file annotations
    (pathandbase, ext) = os.path.splitext(audiofile)
    simfiles = list()
    if os.path.exists(pathandbase): simfiles.append(pathandbase)
    for s in glob(pathandbase+'.*'): simfiles.append(s)
    txt=None

    for simfile in simfiles: # for every file sharing base-name (any or no extension)
        try:
            if not is_binary(simfile): # if its a text file
#                if simfile == audiofile: continue # (we skip the original) #unnecesary; it is_binary

                # copy text (file content) to new track annotation (type txt.[ext])
                txt=open(simfile)
                (xxx, ext) = os.path.splitext(simfile)
                track.annotations.append(Annotation(name=unicode(ext[1:]), value=unicode(txt.read())))
                annots += 1
        finally:
            if type(txt)==file: txt.close()
            
    commit() #saves all appended annotations in the track
    
    log.debug('    Stored %s annotations overall', annots)
    return annots
Beispiel #2
0
def add_track(trackpath, source=str(datetime.date.today()),
              gordonDir=DEF_GORDON_DIR, tag_dict=None, artist=None,
              album=None, fast_import=False, import_md=False):
    """Add track with given filename <trackpath> to database
    
         @param source: audio files data source (string)
         @param gordonDir: main Gordon directory
         @param tag_dict: dictionary of key,val tag pairs - See add_album(...).
         @param artist: The artist for this track. An instance of Artist. None if not present
         @param album: The album for this track. An instance of Album. None if not present
         @param fast_import: If true, do not calculate strip_zero length. Defaults to False
         @param import_md: use True to try to extract all metadata tags embedded in the auudio-file. Defaults to False
    """
    (path, filename) = os.path.split(trackpath) 
    (fname, ext) = os.path.splitext(filename)

    if tag_dict is None:
        tag_dict = {}

    log.debug('Adding file "%s" of "%s" album by %s', filename, album, artist)
    
    # validations
    if 'album' not in tag_dict:
        #todo: currently cannot add singleton files. Need an album which is defined in tag_dict
        log.error('Cannot add "%s" because it is not part of an album',
                  filename)
        return -1 # didn't add
    if not os.path.isfile(trackpath):
        log.info('Skipping %s because it is not a file', filename)
        return -1 # not a file

# FIXME:  2014-01-10 21:42:48 by Brian McFee <*****@*****.**>
#  gordon's AudioFile code doesn't handle unicode filenames correctly
#     try:
#         AudioFile(trackpath).read(tlen_sec=0.01)
#     except:
#         log.error('Skipping "%s" because it is not a valid audio file', filename)
#         return -1 # not an audio file

    # required data
    bytes = os.stat(trackpath)[stat.ST_SIZE]

    # First look for dupes
    if track_exists(filename, bytes):
        log.debug('Skipping "%s" because it has already been indexed', filename)
        return -1 # Already exists

    # prepare data
    
    if tag_dict[u'compilation'] not in [True, False, 'True', 'False'] :
        tag_dict[u'compilation'] = False

    track = Track(title = tag_dict[u'title'],
                  artist = tag_dict[u'artist'],
                  album = tag_dict[u'album'],
                  tracknum = tag_dict[u'tracknum'],
                  compilation = tag_dict[u'compilation'],
                  otitle = tag_dict[u'title'],
                  oartist = tag_dict[u'artist'],
                  oalbum = tag_dict[u'album'],
                  otracknum = tag_dict[u'tracknum'],
                  ofilename = unicode(filename, 'utf-8', errors='ignore'),
                  source = unicode(source),
                  bytes = bytes)
    
    # add data
    add(track) # needed to get a track id
    commit() #to get our track id we need to write this record
    log.debug('Wrote track record %s to database', track.id)

    if fast_import :
        track.secs = -1
        track.zsecs = -1
    else :
        a = AudioFile(trackpath)
        [track.secs, track.zsecs] = a.get_secs_zsecs()
        
    track.path = u'%s' % get_tidfilename(track.id, ext[1:])

    # links track to artist & album in DB
    if artist:
        log.debug('Linking %s to artist %s', track, artist)
        track.artist = artist.name
        track.artists.append(artist)
    if album:
        log.debug('Linking %s to album %s', track, album)
        track.album = album.name
        track.albums.append(album)

    log.debug('Wrote album and artist additions to track into database')

    # copy the file to the Gordon audio/feature data directory
    tgt = os.path.join(gordonDir, 'audio', 'main', track.path)
    make_subdirs_and_copy(trackpath, tgt)
    log.debug('Copied "%s" to %s', trackpath, tgt)
    
    # add annotations
    
    del(tag_dict[u'title'])
    del(tag_dict[u'artist'])
    del(tag_dict[u'album'])
    del(tag_dict[u'tracknum'])
    del(tag_dict[u'compilation'])
    for tagkey, tagval in tag_dict.iteritems(): # create remaining annotations
        track.annotations.append(Annotation(type='text', name=tagkey, value=tagval))
    
    if import_md:
        #check if file is mp3. if so:
        if isValidMP3(trackpath):
            #extract all ID3 tags, store each tag value as an annotation type id3.[tagname]
            for tag in getAllTags(trackpath):
                track.annotations.append(Annotation(type='id3', name=tag[0], value=tag[1]))
        
        #todo: work with more metadata formats (use tagpy?)
    
    # Link the track to the collection object
    track.collections.append(get_or_create_collection(source))
    commit() # store the annotations
    log.debug('Added "%s"', trackpath)
Beispiel #3
0
def add_track(trackpath,
              source=str(datetime.date.today()),
              gordonDir=DEF_GORDON_DIR,
              tag_dict=dict(),
              artist=None,
              album=None,
              fast_import=False,
              import_md=False):
    """Add track with given filename <trackpath> to database
    
         @param source: audio files data source (string)
         @param gordonDir: main Gordon directory
         @param tag_dict: dictionary of key,val tag pairs - See add_album(...).
         @param artist: The artist for this track. An instance of Artist. None if not present
         @param album: The album for this track. An instance of Album. None if not present
         @param fast_import: If true, do not calculate strip_zero length. Defaults to False
         @param import_md: use True to try to extract all metadata tags embedded in the auudio-file. Defaults to False
    """
    (path, filename) = os.path.split(trackpath)
    (fname, ext) = os.path.splitext(filename)

    log.debug('Adding file "%s" of "%s" album by %s', filename, album, artist)

    # validations
    if 'album' not in tag_dict:
        #todo: currently cannot add singleton files. Need an album which is defined in tag_dict
        log.error('Cannot add "%s" because it is not part of an album',
                  filename)
        return -1  # didn't add
    if not os.path.isfile(trackpath):
        log.info('Skipping %s because it is not a file', filename)
        return -1  # not a file
    try:
        AudioFile(trackpath).read(tlen_sec=0.01)
    except:
        log.error('Skipping "%s" because it is not a valid audio file',
                  filename)
        return -1  # not an audio file

    # required data
    bytes = os.stat(trackpath)[stat.ST_SIZE]

    # reencode name to latin1 !!!
    try:
        fn_recoded = filename.decode('utf-8')
    except:
        try:
            fn_recoded = filename.decode('latin1')
        except:
            fn_recoded = 'unknown'

    # prepare data

    if tag_dict[u'compilation'] not in [True, False, 'True', 'False']:
        tag_dict[u'compilation'] = False

    track = Track(title=tag_dict[u'title'],
                  artist=tag_dict[u'artist'],
                  album=tag_dict[u'album'],
                  tracknum=tag_dict[u'tracknum'],
                  compilation=tag_dict[u'compilation'],
                  otitle=tag_dict[u'title'],
                  oartist=tag_dict[u'artist'],
                  oalbum=tag_dict[u'album'],
                  otracknum=tag_dict[u'tracknum'],
                  ofilename=fn_recoded,
                  source=unicode(source),
                  bytes=bytes)

    # add data
    add(track)  # needed to get a track id
    commit()  #to get our track id we need to write this record
    log.debug('Wrote track record %s to database', track.id)

    if fast_import:
        track.secs = -1
        track.zsecs = -1
    else:
        a = AudioFile(trackpath)
        [track.secs, track.zsecs] = a.get_secs_zsecs()

    track.path = u'%s' % get_tidfilename(track.id, ext[1:])

    # links track to artist & album in DB
    if artist:
        log.debug('Linking %s to artist %s', track, artist)
        track.artist = artist.name
        track.artists.append(artist)
    if album:
        log.debug('Linking %s to album %s', track, album)
        track.album = album.name
        track.albums.append(album)

    log.debug('Wrote album and artist additions to track into database')

    # copy the file to the Gordon audio/feature data directory
    tgt = os.path.join(gordonDir, 'audio', 'main', track.path)
    make_subdirs_and_copy(trackpath, tgt)
    log.debug('Copied "%s" to %s', trackpath, tgt)

    # add annotations

    del (tag_dict[u'title'])
    del (tag_dict[u'artist'])
    del (tag_dict[u'album'])
    del (tag_dict[u'tracknum'])
    del (tag_dict[u'compilation'])
    for tagkey, tagval in tag_dict.iteritems():  # create remaining annotations
        track.annotations.append(
            Annotation(type='text', name=tagkey, value=tagval))

    if import_md:
        #check if file is mp3. if so:
        if isValidMP3(trackpath):
            #extract all ID3 tags, store each tag value as an annotation type id3.[tagname]
            for tag in getAllTags(trackpath):
                track.annotations.append(
                    Annotation(type='id3', name=tag[0], value=tag[1]))

        #todo: work with more metadata formats (use tagpy?)

    # Link the track to the collection object
    track.collections.append(get_or_create_collection(source))
    commit()  # store the annotations
Beispiel #4
0
def add_album(albumDir, source = str(datetime.date.today()), gordonDir = DEF_GORDON_DIR, prompt_aname = False, fast_import = False, import_md=False):
    """Add a directory with audio files v 1.2
        * when we do an album we need to read all files in before trying anything
        * we can't just add each track individually. We have to make Artist ids for all artists
        * we will presume that 2 songs by same artist string are indeed same artist
    """
    log.debug('  Adding album "%s" - add_album()', albumDir)
    
    tags_dicts = dict()
    albums = set()
    artists = set()
    
    cwd = os.getcwd()
    os.chdir(albumDir)
    for filename in os.listdir('.') :
        (xxx, ext) = os.path.splitext(filename)
        if not os.path.isdir(os.path.join(cwd, filename)) :
            log.debug('  Checking "%s" ...', filename)
            csvtags = False
            
#            if ext.lower() == '.mp3' : # gets ID3 tags from mp3s
            if id3.isValidMP3(os.path.join(cwd, filename)):
                log.debug('  %s is MP3', filename)
                tags_dicts[filename] = _get_id3_dict(filename)
                if not tags_dicts[filename]['empty']: # non empty tags obtained :)
                    log.debug('  .. w/ ID3 tags', tags_dicts[filename])
                    del(tags_dicts[filename]['empty'])
                tags_dicts[filename]['func'] = 'add_mp3'
                albums.add(tags_dicts[filename]['album'])
                artists.add(tags_dicts[filename]['artist'])
            elif ext.lower() in ['.wav', '.aif', '.aiff']: # since this is wav/aif, use possible csv tags file
            #todo: check for file binary content to determine wether it is wav/aiff instead of extension check...
                if not csvtags : csvtags = _read_csv_tags(os.getcwd(), 'tags.csv')
                log.debug('  %s is %s', filename, ext)
                try: # if csvtags[filename] is not empty:
                    if csvtags[filename] : log.debug('  .. w/ CSV tags (tags.csv)', csvtags[filename])
                    tags_dicts[filename] = csvtags[filename]
                except: # make empty tags on the fly
                    tags_dicts[filename] = _empty_tags()
                tags_dicts[filename]['func'] = 'add_uncomp'
                albums.add(tags_dicts[filename]['album'])
                artists.add(tags_dicts[filename]['artist'])
            else:
                log.debug('  %s is not a supported audio file format', filename)
                
            #todo: work with other non-mp3 audio files/tags!
    
    albums = list(albums)
    
    if len(artists) == 0 :
        os.chdir(cwd)
        log.debug('  Nothing to add')
        return # no songs
    else:
        log.debug('  %d artists in directory: %s', len(artists), artists)
    
    if len(albums) <> 1 :  # if more than 1 album found found in ID3 tags
        if prompt_aname :
            # prompt user to choose an album
            album_name = _prompt_aname(albumDir, tags_dicts, albums, cwd)
            if album_name == False : return # why? see _prompt_aname() -- return
        else :
            os.chdir(cwd)
            log.debug('  Not adding %d album names in album %s %s', len(albums), albumDir, str(albums))
            return # more than one album in directory
    else : # there's only one album in the directory (as should be)
        album_name = albums[0]
    
    #add our album to Album table
    log.debug('  Album has %d recordings', len(tags_dicts))
    albumrec = Album(name = unicode(album_name), trackcount = len(tags_dicts))
#    collection = None
    source = unicode(source)
    match = Collection.query.filter_by(name = source)
    if match.count() == 1:
        log.debug('  Matched source %s in database', match[0])
#        collection = match[0]
#    else:
#        collection = Collection(name=unicode(source))
#    albumrec.collections.append(collection)

    #if we have an *exact* string match we will use the existing artist
    artist_dict = dict()
    for artist in set(artists) :
        match = Artist.query.filter_by(name = artist)
        if match.count() == 1 :
            log.debug('  Matched %s %s in database', artist, match[0])
            artist_dict[artist] = match[0]
            #todo: (eckdoug) what happens if match.count()>1? This means we have multiple artists in db with same 
            # name. Do we try harder to resolve which one? Or just add a new one.  I added a new one (existing code)
            # but it seems risky.. like we will generate lots of new artists. 
            # Anyway, we resolve this in the musicbrainz resolver....
        else :
            # add our Artist to artist table
            newartist = Artist(name = unicode(artist))
#            newartist.collections.append(collection)
            artist_dict[artist] = newartist

        #add artist to album (album_artist table)
        albumrec.artists.append(artist_dict[artist])

    commit() #commit these changes in order to have access to this album record when adding tracks

    #now add our tracks to album
    for file in tags_dicts.keys() :
        # calls add_mp3(), add_uncomp(), or other...
        addfunction = tags_dicts[file].pop('func')
        eval(addfunction + "(file, source, gordonDir, tags_dicts[file], artist_dict[tags_dicts[file]['artist']], albumrec, fast_import, import_md)")
        log.debug('  Added "%s"!', file)

    #now update our track counts
    for aname, artist in artist_dict.iteritems() :
        artist.update_trackcount()
        log.debug('  * Updated trackcount for artist %s', artist)
    albumrec.update_trackcount()
    log.debug('  * Updated trackcount for album %s', albumrec) 
    commit()

    os.chdir(cwd) # and return to original working dir