domenica 3 aprile 2011

cd database

with a little help from http://stackoverflow.com/questions/3740903/python-dbus-how-to-export-interface-property

L'altra settimana ho comprato un po' di cd su play.com, approfittando di una bella promozione in cui un sacco di robba stava a 6 euri e mezzo.

Li ho comprati la sera, vagando nell'immenso elenco di disponibilità, ma.... di 8 cd 2 ce li avevo dei già! È il problema di ascoltare la musica in mp3... e anche di avere un sacco di cd! Uno ho fatto in tempo a "rigettarlo", l'altro l'ho regalato, quindi poco male.

Però non è possibile avere 'sti problemi! Mi serve un elenco dei miei cd! Ma come?

Sono pigro, quindi ho subito scartato un elenco amanuense, tipo prendersi tutti i cd e appuntarseli da qualche parte (cartacea o informatica). Mi è venuto in mente che, siccome stanno andando di moda i codici a barre, grazie a smartfon e affini, magari sarebbe stato semplice collegare i codici a barre con i vari cd... ma così semplice mica l'ho trovata!

E allora mi sono risolto alla soluzione che vi incollo qui sotto: uno script (effettivamente linux only) che rileva quando un cd viene inserito, e se non era già presente, lo aggiunge ad un database. Le informazioni su titolo e interprete lo pesca dai database dei cd in rete.

Il tutto in python ovviamente. È particolarmente semplice perchè per interrogare i database c'è il modulo cddb, per interagire con i database ho utilizzato sqlalchemy, e per rilevare se il cd fosse inserito ho utilizzato dbus. Quest'ultimo mi dà la possibilità di controllare il cd chiedendolo a gnome, che lo fa di mestiere, cosicchè è una richiesta rapidissima e indolore. L'utilizzo di dbus è la parte che rende lo script linux-only, eventualmente si dovrebbe trovare l'analogo per il sistema interessato (o per sistemi che non utilizzino dbus ^_^).

Ma come funzia? Abbastanza semplice... il programma ogni secondo controlla che non sia stato inserito un cd, se lo è, prende il suo numero identificativo e vede se non sia già stato memorizzato. Se non lo trova, richiede i dati via internet e lo memorizza. Se lo trova, basta. E finchè non viene tolto il cd, niente più.

È un po' una cosa da gestire bene (e meglio) il fatto che ad un dato codice identificativo di cd possono corrispondere più descrizioni del database online, a volte di cd completamente differenti (lateralus dei tool per esempio corrisponde anche ad un album dei clawfinger [mai sentiti]), ma per adesso funziona.

Quel che ho fatto dunque è prendere tutti i miei cd ed inserirli nel drive. Ora ho l'elenco dei miei cd! Che a sto punto posterò prossimamente.

Ecco lu programma, so far:
import dbus
from time import sleep
import CDDB, DiscID

from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, create_engine
from sqlalchemy.orm import mapper, sessionmaker

def dbus_init(dev):
    bus = dbus.SystemBus()
    ud_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
    ud_manager = dbus.Interface(ud_manager_obj, 'org.freedesktop.UDisks')

    device_obj = bus.get_object("org.freedesktop.UDisks", dbus.ObjectPath(dev) ) #'/dev/sr0')
    device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE)
    return device_props

def cd_data():
    cdrom = DiscID.open()
    disc_id = DiscID.disc_id(cdrom)
    
    (query_status, query_info) = CDDB.query(disc_id)
    #print query_status, query_info, type(query_info),type({})
    if query_status == 200: #successo!!
        (read_status, read_info) = CDDB.read(query_info['category'], query_info['disc_id'])
    elif query_status == 210: #piu successi!!
        none=1
        for entry in query_info:
            if entry['category'] == 'rock':
                (read_status, read_info) = CDDB.read(entry['category'], entry['disc_id'])
                none=0
        if none:
            (read_status, read_info) = CDDB.read(query_info[0]['category'], query_info[0]['disc_id'])
    else:
        print 'album unknown' 
        return None

    #print (read_status, read_info), (query_status, query_info)
    #print read_info['DTITLE']
    [artist, album]=[i.strip() for i in read_info['DTITLE'].split('/',1)]

    return {
        'artist': unicode(artist,'latin-1'),
        'album': unicode(album,'latin-1'),
        'year': unicode(read_info['DYEAR'],'latin-1'),
        'genre': unicode(read_info['DGENRE'],'latin-1'),
        'id': unicode(read_info['DISCID'],'latin-1')
        }

class CdDb(object):
    def __init__(self, artist, album, year, genre, id):
        self.artist = artist
        self.album = album
        self.year = year
        self.genre = genre
        self.id = id
        
    def __repr__(self):
        return "'%s','%s'" % (self.artist, self.album)

def setup_db():
    engine = create_engine('sqlite:///cddb.db', echo=False)
    metadata = MetaData()
    
    users_table = Table('album', metadata,
                        Column('id',  String(50), primary_key=True),
                        Column('artist', String(50)),
                        Column('album',  String(50)),
                        Column('year',   String(50)),
                        Column('genre',  String(50)),
                        Column('name', String(50))
                        )
    metadata.create_all(engine) 
    mapper(CdDb, users_table)
    Session = sessionmaker(bind=engine)

    return Session()

def db_add(cd_data_dic,session):
    if cd_data_dic is not None:
        if len(session.query(CdDb).filter_by(id=cd_data_dic['id']).all()) == 0:
            session.add(
                CdDb(cd_data_dic['artist'], cd_data_dic['album'], cd_data_dic['year'], cd_data_dic['genre'], cd_data_dic['id'])
                )
            session.commit()
            print 'added', cd_data_dic['artist'], cd_data_dic['album'], cd_data_dic['year'], cd_data_dic['genre'], cd_data_dic['id']
        else:
            print 'already in the db as',session.query(CdDb).filter_by(id=cd_data_dic['id']).all()

if __name__ == "__main__":
    device_props = dbus_init('/org/freedesktop/UDisks/devices/sr0')

    session = setup_db()
    pre = 0
    #setup db
    while True:
        #add check if is audiocd
        if device_props.Get('org.freedesktop.UDisks.Device', "PartitionSize") != 0 and pre == 0:
            #print device_props.Get('org.freedesktop.UDisks.Device', "PartitionSize")
            db_add(cd_data(),session)
            pre = 1
        elif device_props.Get('org.freedesktop.UDisks.Device', "PartitionSize") == 0 and pre == 1:
            pre= 0
        sleep(1)

Nessun commento:

Posta un commento