/* This file is part of the KDE project * Copyright (C) 2001, 2002 Rolf Magnus * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * $Id$ */ #include "kfile_ogg.h" #include "vcedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // known translations for common ogg/vorbis keys // from http://www.ogg.org/ogg/vorbis/doc/v-comment.html static const char* const knownTranslations[] = { I18N_NOOP("Title"), I18N_NOOP("Version"), I18N_NOOP("Album"), I18N_NOOP("Tracknumber"), I18N_NOOP("Artist"), I18N_NOOP("Organization"), I18N_NOOP("Description"), I18N_NOOP("Genre"), I18N_NOOP("Date"), I18N_NOOP("Location"), I18N_NOOP("Copyright") // I18N_NOOP("Isrc") // dunno what an Isrc number is, the link is broken }; K_EXPORT_COMPONENT_FACTORY(kfile_ogg, KGenericFactory("kfile_ogg")) KOggPlugin::KOggPlugin( TQObject *parent, const char *name, const TQStringList &args ) : KFilePlugin( parent, name, args ) { kdDebug(7034) << "ogg plugin\n"; KFileMimeTypeInfo* info = addMimeTypeInfo( "audio/vorbis" ); KFileMimeTypeInfo::GroupInfo* group = 0; // comment group group = addGroupInfo(info, "Comment", i18n("Comment")); setAttributes(group, KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable); KFileMimeTypeInfo::ItemInfo* item = 0; item = addItemInfo(group, "Artist", i18n("Artist"), TQVariant::String); setHint(item, KFileMimeTypeInfo::Author); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Title", i18n("Title"), TQVariant::String); setHint(item, KFileMimeTypeInfo::Name); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Album", i18n("Album"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Genre", i18n("Genre"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Tracknumber", i18n("Track Number"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Date", i18n("Date"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Description", i18n("Description"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Organization", i18n("Organization"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Location", i18n("Location"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); item = addItemInfo(group, "Copyright", i18n("Copyright"), TQVariant::String); setAttributes(item, KFileMimeTypeInfo::Modifiable); addVariableInfo(group, TQVariant::String, KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable | KFileMimeTypeInfo::Modifiable); // technical group group = addGroupInfo(info, "Technical", i18n("Technical Details")); setAttributes(group, 0); addItemInfo(group, "Version", i18n("Version"), TQVariant::Int); addItemInfo(group, "Channels", i18n("Channels"), TQVariant::Int); item = addItemInfo(group, "Sample Rate", i18n("Sample Rate"), TQVariant::Int); setSuffix(item, i18n(" Hz")); item = addItemInfo(group, "UpperBitrate", i18n("Upper Bitrate"), TQVariant::Int); setSuffix(item, i18n(" kbps")); item = addItemInfo(group, "LowerBitrate", i18n("Lower Bitrate"), TQVariant::Int); setSuffix(item, i18n(" kbps")); item = addItemInfo(group, "NominalBitrate", i18n("Nominal Bitrate"), TQVariant::Int); setSuffix(item, i18n(" kbps")); item = addItemInfo(group, "Bitrate", i18n("Average Bitrate"), TQVariant::Int); setAttributes(item, KFileMimeTypeInfo::Averaged); setHint(item, KFileMimeTypeInfo::Bitrate); setSuffix(item, i18n( " kbps")); item = addItemInfo(group, "Length", i18n("Length"), TQVariant::Int); setAttributes(item, KFileMimeTypeInfo::Cummulative); setUnit(item, KFileMimeTypeInfo::Seconds); } bool KOggPlugin::readInfo( KFileMetaInfo& info, uint what ) { // parts of this code taken from ogginfo.c of the vorbis-tools v1.0rc2 FILE *fp; OggVorbis_File vf; int rc,i; vorbis_comment *vc; vorbis_info *vi; bool readComment = false; bool readTech = false; if (what & (KFileMetaInfo::Fastest | KFileMetaInfo::DontCare | KFileMetaInfo::ContentInfo)) readComment = true; if (what & (KFileMetaInfo::Fastest | KFileMetaInfo::DontCare | KFileMetaInfo::TechnicalInfo)) readTech = true; memset(&vf, 0, sizeof(OggVorbis_File)); if ( info.path().isEmpty() ) // remote file return false; fp = fopen(TQFile::encodeName(info.path()),"rb"); if (!fp) { kdDebug(7034) << "Unable to open " << TQFile::encodeName(info.path()) << endl; return false; } rc = ov_open(fp,&vf,NULL,0); if (rc < 0) { kdDebug(7034) << "Unable to understand " << TQFile::encodeName(info.path()) << ", errorcode=" << rc << endl; return false; } // info.insert(KFileMetaInfoItem("Vendor", i18n("Vendor"), // TQVariant(TQString(vi->vendor)))); // get the vorbis comments if (readComment) { vc = ov_comment(&vf,-1); KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment"); for (i=0; i < vc->comments; i++) { kdDebug(7034) << vc->user_comments[i] << endl; TQStringList split = TQStringList::split("=", TQString::fromUtf8(vc->user_comments[i])); split[0] = split[0].lower(); split[0][0] = split[0][0].upper(); // we have to be sure that the i18n() string always has the same // case. Oh, and is UTF8 ok here? appendItem(commentGroup, split[0], split[1]); } } if (readTech) { KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); // get other information about the file vi = ov_info(&vf,-1); if (vi) { appendItem(techgroup, "Version", int(vi->version)); appendItem(techgroup, "Channels", int(vi->channels)); appendItem(techgroup, "Sample Rate", int(vi->rate)); if (vi->bitrate_upper > 0) appendItem(techgroup, "UpperBitrate", int(vi->bitrate_upper+500)/1000); if (vi->bitrate_lower > 0) appendItem(techgroup, "LowerBitrate", int(vi->bitrate_lower+500)/1000); if (vi->bitrate_nominal > 0) appendItem(techgroup, "NominalBitrate", int(vi->bitrate_nominal+500)/1000); if (ov_bitrate(&vf,-1) > 0) appendItem(techgroup, "Bitrate", int(ov_bitrate(&vf,-1)+500)/1000); } appendItem(techgroup, "Length", int(ov_time_total(&vf,-1))); } ov_clear(&vf); return true; } bool KOggPlugin::writeInfo(const KFileMetaInfo& info) const { // todo: add writing support FILE* infile; infile = fopen(TQFile::encodeName(info.path()), "r"); if (!infile) { kdDebug(7034) << "couldn't open " << info.path() << endl; return false; } vcedit_state *state=vcedit_new_state(); if ( vcedit_open(state, infile)==-1 ) { kdDebug(7034) << "error in vcedit_open for " << info.path() << endl; return false; } struct vorbis_comment* oc = vcedit_comments(state); struct vorbis_comment* vc = state->vc; if(vc) vorbis_comment_clear(vc); if (oc && oc->vendor) { vc->vendor = strdup(oc->vendor); } else { vc->vendor = strdup(""); } KFileMetaInfoGroup group = info["Comment"]; TQStringList keys = group.keys(); TQStringList::Iterator it; for (it = keys.begin(); it!=keys.end(); ++it) { KFileMetaInfoItem item = group[*it]; if (!item.isEditable() || !(item.type()==TQVariant::String) ) continue; TQCString key = item.key().upper().utf8(); if (item.value().canCast(TQVariant::String)) { TQCString value = item.value().toString().utf8(); kdDebug(7034) << " writing tag " << key << "=" << value << endl; vorbis_comment_add_tag(vc, const_cast(static_cast(key)), const_cast(static_cast(value))); } else kdWarning(7034) << "ignoring " << key << endl; } TQString filename; TQFileInfo fileinfo(info.path()); // follow symlinks if (fileinfo.isSymLink()) filename = fileinfo.readLink(); else filename = info.path(); // nothing in Qt or KDE to get the mode as an int? struct stat s; stat(TQFile::encodeName(filename), &s); KSaveFile sf(filename, s.st_mode); FILE* outfile = sf.fstream(); if ( sf.status() || !outfile) { kdDebug(7034) << "couldn't create temp file\n"; vcedit_clear(state); // frees comment entries and vendor sf.abort(); if (vc->vendor) free(vc->vendor); vc->vendor = 0; return false; } vcedit_write(state,outfile); // calls vcedit_clear() itself so we don't free anything if (vc->vendor) free(vc->vendor); vc->vendor = 0; fclose(infile); sf.close(); return true; } TQValidator* KOggPlugin::createValidator( const TQString&, const TQString &, const TQString &, TQObject* parent, const char* name) const { return new TQRegExpValidator(TQRegExp(".*"), parent, name); } #include "kfile_ogg.moc"