[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    kfile_mp3 patch to support id3v2 tags
From:       MadCoder <pierre.habouzit () m4x ! org>
Date:       2002-10-25 19:15:58
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

the files are both in kdemultimedia/kfile-plugins/mp3/

This new version is fully compatible with the previous one, and works 
perfectly under 3.0.x versions.

its works so :
 * reading :
   - if there is an id3v1(.1) tag, let the old fashion
     that is pretty fast work.
   - if there isn't any, try to read id3v2.

 * wrinting :
   - if the new tag is not valid (to long headers for example),
     it writes an id3v2 tag, and strips the id3v1. if it's valid for
     an id3v1, it writes it, and strip id3v2.
   - if there is lyrics, it allways writes id3v2 tags.

this use id3lib, thats why i needed to modify the Makefile.am

what do you think about it ?
- -- 
MadCoder (51 57)

Linux, c'est comme la France, ce serait le + beau pays du monde s'il
n'était pas peuplé par des arrogants, suffisants pensants détenir
tout le savoir du monde...
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE9uZhuxB6ZXMmMkL4RAhdeAJ4irQ/vNUUjVBUejUbZ55QyLguWAQCfVTCA
PJe94frDHKIFxtW3qH7zA3U=
=tIXb
-----END PGP SIGNATURE-----

["kfile_mp3.cpp" (text/x-c++src)]

/* This file is part of the KDE project
 * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org>
 * Copyright (C) 2002 Ryan Cumming <bodnar42@phalynx.dhs.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation version 2.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *  $Id: kfile_mp3.cpp,v 1.49 2002/10/12 16:01:42 wheeler Exp $
 */
#include "kfile_mp3.h"

#include <id3/field.h>
#include <id3/tag.h>
#include <id3/misc_support.h>

#include <kprocess.h>
#include <klocale.h>
#include <kgenericfactory.h>
#include <kstringvalidator.h>
#include <kdebug.h>

#include <qdict.h>
#include <qvalidator.h>
#include <qcstring.h>
#include <qfile.h>
#include <qdatetime.h>

// need this for the mp3info header
#define __MAIN
extern "C" {
#include "mp3info.h"
}
#undef __MAIN

typedef KGenericFactory<KMp3Plugin> Mp3Factory;

K_EXPORT_COMPONENT_FACTORY(kfile_mp3, Mp3Factory( "kfile_mp3" ));

KMp3Plugin::KMp3Plugin(QObject *parent, const char *name,
                       const QStringList &args)
    
    : KFilePlugin(parent, name, args)
{
    kdDebug(7034) << "mp3 plugin\n";
    
    KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/x-mp3" );

    KFileMimeTypeInfo::GroupInfo* group = 0L;

    // id3 group v1.1
//    group = addGroupInfo(info, "id3v1.1", i18n("ID3V1 Tag"));
    group = addGroupInfo(info, "id3v1.1", "ID3V1 Tag");
    setAttributes(group, KFileMimeTypeInfo::Addable |
                         KFileMimeTypeInfo::Removable);

    KFileMimeTypeInfo::ItemInfo* item;

    item = addItemInfo(group, "Title", i18n("Title"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);
    setHint(item,  KFileMimeTypeInfo::Name);

    item = addItemInfo(group, "Artist", i18n("Artist"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);
    setHint(item,  KFileMimeTypeInfo::Author);

    item = addItemInfo(group, "Album", i18n("Album"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);

    item = addItemInfo(group, "Date", i18n("Year"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);

    item = addItemInfo(group, "Comment", i18n("Comment"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);
    setHint(item,  KFileMimeTypeInfo::Description);

    item = addItemInfo(group, "Tracknumber", i18n("Track"), QVariant::Int);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);

    item = addItemInfo(group, "Genre", i18n("Genre"), QVariant::String);
    setAttributes(item, KFileMimeTypeInfo::Modifiable);

    // technical group
    group = addGroupInfo(info, "Technical", i18n("Technical Details"));

    item = addItemInfo(group, "Version", i18n("Version"), QVariant::Int);
    setPrefix(item,  i18n("MPEG"));

    item = addItemInfo(group, "Layer", i18n("Layer"), QVariant::Int);
    item = addItemInfo(group, "CRC", i18n("CRC"), QVariant::Bool);
    item = addItemInfo(group, "Bitrate", i18n("Bitrate"), QVariant::Int);
    setAttributes(item, KFileMimeTypeInfo::Averaged);
    setHint(item, KFileMimeTypeInfo::Bitrate);
    setSuffix(item, i18n(" kbps"));

    item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), QVariant::Int);
    setSuffix(item, i18n("Hz"));
    
    item = addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int);
    item = addItemInfo(group, "Copyright", i18n("Copyright"), QVariant::Bool);
    item = addItemInfo(group, "Original", i18n("Original"), QVariant::Bool);
    item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int);
    setAttributes(item,  KFileMimeTypeInfo::Cummulative);
    setUnit(item, KFileMimeTypeInfo::Seconds);
    item = addItemInfo(group, "Emphasis", i18n("Emphasis"), QVariant::String);
}

bool KMp3Plugin::readInfo( KFileMetaInfo& info, uint what )
{
    kdDebug(7034) << "mp3 plugin readInfo\n";

    bool readId3 = false;
    bool readTech = false;
    typedef enum KFileMetaInfo::What What;
    if (what & (KFileMetaInfo::Fastest |
                KFileMetaInfo::DontCare |
                KFileMetaInfo::ContentInfo)) readId3 = true;

    if (what & (KFileMetaInfo::Fastest |
                KFileMetaInfo::DontCare |
                KFileMetaInfo::TechnicalInfo)) readTech = true;

    mp3info mp3;

    memset(&mp3,0,sizeof(mp3info));

    QCString s = QFile::encodeName(info.path());
    mp3.filename = new char[s.length()+1];
    strcpy(mp3.filename, s);

    mp3.file = fopen(mp3.filename, "rb");
    if (!mp3.file)
    {
        delete [] mp3.filename;
        kdDebug(7034) << "Couldn't open " << mp3.filename << endl;
        return false;
    }

    ::get_mp3_info(&mp3, ::SCAN_QUICK, ::VBR_VARIABLE);
    
    // id3 v1.1 part

    if (mp3.id3_isvalid && readId3)
    {
        KFileMetaInfoGroup id3group = appendGroup(info, "id3v1.1");

        appendItem(id3group, "Title", QString::fromLocal8Bit(mp3.id3.title));
        appendItem(id3group, "Artist", QString::fromLocal8Bit(mp3.id3.artist));
        appendItem(id3group, "Album", QString::fromLocal8Bit(mp3.id3.album));
        appendItem(id3group, "Date", QString::fromLocal8Bit(mp3.id3.year));
        appendItem(id3group, "Comment", QString::fromLocal8Bit(mp3.id3.comment));

        if (mp3.id3.track[0])
            appendItem(id3group, "Tracknumber", mp3.id3.track[0]);

        // Could we find a valid genre?
        if (mp3.id3.genre[0]>MAXGENRE) {
            // No, set it to 12 ("Other")
                mp3.id3.genre[0] = 12;
        }

        appendItem(id3group, "Genre", QString::fromLocal8Bit(
                                              ::typegenre[mp3.id3.genre[0]]));
    }
    else {
	memset(&mp3.id3, sizeof(id3tag), 0);
	if(readId3) {
	    // ID3V2 stuff
	    ID3_Tag * id3v2 = new ID3_Tag();
	    id3v2->Link(mp3.filename, (short unsigned int)ID3TT_ID3V2);

	    KFileMetaInfoGroup id3group = appendGroup(info, "id3v1.1");

	    appendItem(id3group, "Title", QString::fromLocal8Bit(ID3_GetTitle(id3v2)));
	    appendItem(id3group, "Artist", QString::fromLocal8Bit(ID3_GetArtist(id3v2)));
	    appendItem(id3group, "Album", QString::fromLocal8Bit(ID3_GetAlbum(id3v2)));
	    appendItem(id3group, "Date", QString::fromLocal8Bit(ID3_GetYear(id3v2)));
	    appendItem(id3group, "Comment", QString::fromLocal8Bit(ID3_GetComment(id3v2)));
	    appendItem(id3group, "Tracknumber", QString::fromLocal8Bit(ID3_GetTrack(id3v2)));

	    int genre = (ID3_GetGenreNum(id3v2)>MAXGENRE ? 12 : ID3_GetGenreNum(id3v2));
	    appendItem(id3group, "Genre", QString::fromLocal8Bit( ::typegenre[genre]));
	    delete id3v2;
	}
    }
    // end of the id3 part

    // now the technical stuff
    if (mp3.header_isvalid && readTech) {

        KFileMetaInfoGroup techgroup = appendGroup(info, "Technical");
        
        appendItem(techgroup, "Version", mp3.header.version);
        appendItem(techgroup, "Layer", ::header_layer(&mp3.header));
        appendItem(techgroup, "CRC", QVariant(header_crc(&mp3.header), 42));
        appendItem(techgroup, "Bitrate", ::header_bitrate(&mp3.header));
        appendItem(techgroup, "Sample Rate", ::header_frequency(&mp3.header));
        // Modes 0-2 are forms of stereo, mode 3 is mono
        appendItem(techgroup, "Channels", int((mp3.header.mode == 3) ? 1 : 2));
        appendItem(techgroup, "Copyright", QVariant(mp3.header.copyright, 42));
        appendItem(techgroup, "Original", QVariant(mp3.header.original, 42));
        appendItem(techgroup, "Length", mp3.seconds);
        appendItem(techgroup, "Emphasis", QString(::header_emphasis(&mp3.header)));
    }

    fclose(mp3.file);
    kdDebug(7034) << "reading finished\n";
    
    delete [] mp3.filename;
    
    return true;
}

bool KMp3Plugin::writeInfo( const KFileMetaInfo& info) const
{
    ID3_Tag * id3v2 = new ID3_Tag();
    if(!id3v2->Link(info.path().local8Bit(), ID3TT_ID3V1));
	id3v2->Link(info.path().local8Bit(), ID3TT_ID3V2);

    QCString temp;

    temp = info["id3v1.1"]["Title"].value().toString().local8Bit();
    if(temp.isEmpty())
	ID3_RemoveTitles(id3v2);
    else
	ID3_AddTitle(id3v2, temp, true);

    temp = info["id3v1.1"]["Artist"].value().toString().local8Bit();
    if(temp.isEmpty())
	ID3_RemoveArtists(id3v2);
    else
	ID3_AddArtist(id3v2, temp, true);

    temp = info["id3v1.1"]["Album"].value().toString().local8Bit();
    if(temp.isEmpty())
	ID3_RemoveAlbums(id3v2);
    else
	ID3_AddAlbum(id3v2, temp, true);

    temp = info["id3v1.1"]["Date"].value().toString().local8Bit();
    if(temp.isEmpty())
	ID3_RemoveYears(id3v2);
    else
	ID3_AddYear(id3v2, temp, true);

    temp = info["id3v1.1"]["Comment"].value().toString().local8Bit();
    if(temp.isEmpty())
	ID3_RemoveComments(id3v2);
    else
	ID3_AddComment(id3v2, temp, true);

    KFileMetaInfoItem track = info["id3v1.1"]["Tracknumber"];
    if (track.isValid())
	ID3_AddTrack(id3v2, track.value().toInt(), 0, true);
    else
	ID3_RemoveTracks(id3v2);

    QString s = info["id3v1.1"]["Genre"].value().toString();
    int genre;

    for (genre = 0; genre <= MAXGENRE; genre++)
	if (s == ::typegenre[genre])
	    break;

    if (genre > MAXGENRE) genre = 12;
	ID3_AddGenre(id3v2, genre, true);

    if (info.groups().contains("id3v1.1"))
    // write id3v1 if file has lyrics ...
	if(info["id3v1.1"].isValid() && !id3v2->HasLyrics())
	{
	    id3v2->Strip(ID3TT_ID3V2);
	    id3v2->Update(ID3TT_ID3V2);
	} else {
	    id3v2->Strip(ID3TT_ID3V1);
	    id3v2->Update(ID3TT_ID3V2);
	}
    else
	id3v2->Strip();

    delete id3v2;
    return true;
}

QValidator* KMp3Plugin::createValidator(const QString& /* mimetype */,
                                        const QString &group, const QString &key,
                                        QObject* parent, const char* name) const
{
    kdDebug(7034) << "making a validator for " << group << "/" << key << endl;

    if ((key == "Title") || (key == "Artist")||
        (key == "Album"))
    {
	return new QRegExpValidator(QRegExp(".{,30}"), parent, name);
    }
    else if (key == "Date")
    {
        return new QRegExpValidator(QRegExp(".{,4}"), parent, name);
    }
    else if (key == "Comment")
    {
	return new QRegExpValidator(QRegExp(".{,28}"), parent, name);
    }
    else if (key == "Tracknumber")
    {
	return new QIntValidator(0, 255, parent, name);
    }
    else if (key == "Genre")
    {
        QStringList list;
        for (int index = 0; index <= MAXGENRE; index++)
        {
           list += ::typegenre[galphagenreindex[index]];
         }

        return new KStringListValidator(list, false, true, parent, name);
    }
    return 0;
}

#include "kfile_mp3.moc"

["Makefile.am" (text/x-makefile)]

## Makefile.am for mp3 file meta info plugin

# set the include path for X, qt and KDE
INCLUDES         = $(all_includes)

# these are the headers for your project
noinst_HEADERS   = kfile_mp3.h mp3tech.h mp3info.h

kde_module_LTLIBRARIES = kfile_mp3.la

kfile_mp3_la_SOURCES = kfile_mp3.cpp mp3tech.c
kfile_mp3_la_LDFLAGS = $(all_libraries) -module -lid3 $(KDE_PLUGIN)
kfile_mp3_la_LIBADD = $(LIB_KIO)

# let automoc handle all of the meta source files (moc)
METASOURCES = AUTO

messages: rc.cpp
	$(XGETTEXT) kfile_mp3.cpp -o $(podir)/kfile_mp3.pot

services_DATA = kfile_mp3.desktop
servicesdir = $(kde_servicesdir)

>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic