> Just tell me. It is easy to add new functions to the parsing and
> caching routine.

it's late right now (for me[NL])... 
but out the top of my head:

-ape-tag parsing in mmpython --> I must send in a patch but
apev2tag.py has changed recently,i have to make a new good patch
again.

-all possible mp3 tags (including user defined) like album_artist
(foobar2000) should be in the meta database.

-data like like rating and play_counter should be written to mp3 tags-tags
The meta database should be a cache of the real data , and may never
contain any new data (right now play_counter and rating are in the
sqlite-db but not in the tags)

-when bug  #1170064 is fixed (just rename audio/plugins/playlist.py to
something else) is fixed i will make a freevo CVS compatible  version
of audio_album_tree.

-I did some test in comparing an unindexed sqlite database to a python
list of dicts(or objects) and the speed(after loading into memory) of
a python pickle/marshall is higher than unindexed sqlite db.

but unindexed sqlite is still fast enough.
Prototype  of a user-(pre)defined sqlite database with custom tags
using a "hacked" mmpython:
"""
concept for a dynamic meta database for freevo.
assumes everyone uses different mp3-tags
fields is a tuple/list that contains the tags to be added to the meta-database.
includes automatic schema updates if "fields" changes
NOTE: REQUIRES A HACKED VERSION OF MMPYTHON(because i want my ape-tags.)
"""

import  mmpython 
import sqlite 
import sys
import os 

try:    
    import psyco
    psyco.full()
    print 'PSYCO!' 
except:
    print 'no spyco.'     

enc = sys.getdefaultencoding() 
 
mmpython.audio.mp3taginfo.READ_ORDER = ('apev2','id3v1') #id3v2 is
evil ;) , i do not use or support it.
mmpython.audio.mp3taginfo.READ_ALL   = False 
 

#problem tags:
#lastplayed is used by freevo as a timestamp,
#,timestamps are not readable in a tag, i would prefer ape format
(TODO:search link)
#same for lastplayed.

#my preferred way of storing datetime:                
#http://wiki.hydrogenaudio.org/index.php?title=Foobar2000_Encouraged_Tag_Standards#LAST_PLAYED
#http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/sv8/time.html
#


class Tag(object):
    """
    name=name in database
    type=python-type (allowed are int,str,float)
    """
    type=str
    #data class
    def __init__(self,name,tagname=None):    
        self.name = name
        if tagname:
            self.tagname = tagname
        else:
            self.tagname = name
        
    def tag2db(self,value):
        return unicode(value)

class TagInt(Tag):
    type=int

class TagFloat(Tag):
    type=float   
   
    
class TagRg(TagFloat):    
    """
    replaygain tag must be cleaned up on reading
    tag contains -1.111 DB , must return -1.111
    """
    def tag2db(self,value):
        if value:
            return unicode(value.split[0])      


class TagYYYYMMDD(Tag):
    def tag2db(self,value):
        if value:
            return unicode(value[0:4]+'-'+value[4:6]+'-'+value[6:8])        

systemfields = [TagInt('id'),Tag('dirtitle'), Tag('path'), Tag('filename')]
#, Tag('start_time'), Tag('end_time'),

fields = [    
     Tag('artist'),Tag('album'),TagInt('track',tagname='trackno'),Tag('title')
     , TagInt('year',tagname='date')
     ,Tag('comment'),Tag('genre'),TagInt('length')
    , TagInt('track_total',tagname='trackof')
    , TagInt('bpm')
    ,TagInt('bitrate')
    ,TagRg('replaygain_album_gain'),TagRg('replaygain_track_gain')
    ,Tag('album_artist')
    #,TagFloat('replaygain_track_peak')    
    ,Tag('origin'),TagYYYYMMDD('date_add'),Tag('last_played')
    #, Tag('type')
    ,TagInt('play_count',tagname='play_counter')
    ,TagInt('rating')    
]

allfields = systemfields + fields

dbschema =  """CREATE TABLE music (id INTEGER PRIMARY KEY 
, dirtitle VARCHAR(255), path VARCHAR(255), filename VARCHAR(255) """ 
for field in fields: 
    if field.type == str: 
        dbschema += '\n,%s VARCHAR(255)' % field.name 
    elif field.type == int: 
        dbschema += '\n,%s INTEGER' % field.name
    elif field.type == float:
        dbschema += '\n,%s NUMERIC' % field.name
         
dbschema+=')' 
 
db = sqlite.Connection('./musicdb_test.sqlite',encoding='utf-8') 
cursor = db.cursor() 
#table versioning by exact same create string.
#update schema if needed. 
cursor.execute("SELECT sql FROM sqlite_master where name = 'music'")
if not cursor.rowcount:
    print 'CREATING music TABLE'
    cursor.execute(dbschema)
    db.commit()
else:
    currentschema = cursor.fetchone()[0]
    if currentschema <> dbschema: 
        print 'DB SHEMA WAS MODIFIED:DROPPING music TABLE' 
        cursor.execute('DROP TABLE music') 
        cursor.execute(dbschema) 
        db.commit()
    
     
def update_or_create(musicfile,info):
    """
    update meta-database
    """ 
    id = None 
    cursor.execute('select id from music where path=%s and
filename=%s',os.path.dirname(musicfile),os.path.basename(musicfile))
    result = cursor.fetchone() 
    if result: 
        id = result.id 
        print 'update:',id 
        dbdict = {} 
    else: 
        dbdict =
{'filename':os.path.basename(musicfile),'path':os.path.dirname(musicfile)}
    for field in fields:
        #print field.name, field,dir(field) 
        if field.tagname in info.keys: #tag found:copy tag do
dbdict(TODO:SET enc to iso???? instead of ascii)
            try: 
                dbdict[field.name] = unicode(info[field.tagname],enc) 
            except: 
                dbdict[field.name] = 'unicode-error' 
        else: #no tag:set default value in dbdict
            #rint 'no-tag:',field.name 
            if field.type in (int,float):  
                dbdict[field.name] = 0 
            else: 
                dbdict[field.name] = None
     
    if id == None: 
        #insert into  music (comment,title,dirname,artist) values (%s,%s,%s,%s) 
        dbquery = 'insert into  music (%s) values (%s)' %( 
                    ','.join(dbdict.keys()) 
                    ,','.join(['%s']*len(dbdict.keys())))  
        #2 args to cursor.execute:let pysqlite figure out quoting etc. 
        cursor.execute(dbquery,dbdict.values()) 
    else:   
        dbquery = 'update music set '         
        #comment=%s ,album=%s ,title=%s  etc..         
        dbquery += ','.join([key+'=%s ' for key in dbdict.keys()]) 
        dbquery += 'where id=%s' % id 
        #2 args to cursor.execute:let pysqlite figure out quoting etc. 
        cursor.execute(dbquery,dbdict.values()) 
         
#testing,fill some data intomthe database
for (dirpath, dirnames, filenames) in os.walk('/mnt/hdc2/data/mp3'):
    for filename in filenames:
        #print filename
        if not filename.lower().endswith('mp3'):
            continue
            
        musicfile = os.path.join(dirpath,filename)
        try: 
            temp = unicode(musicfile,enc) 
        except: 
            print 'unicode-error! on',musicfile 
            continue 
        print 'parsing..',musicfile 
        info = mmpython.parse(musicfile)    
        #for k in info.keys:
        #   print k,'=',info[k]
        #sys.exit(0)
        
        if not info: 
            continue #no tag->not in database 
        update_or_create(musicfile,info)
                 
print 'commit...'     
db.commit()    
print 'END'


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Freevo-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-devel

Reply via email to