summaryrefslogtreecommitdiffstats
path: root/kaffeine/src/player-parts/kaffeine-part
diff options
context:
space:
mode:
Diffstat (limited to 'kaffeine/src/player-parts/kaffeine-part')
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/Makefile.am12
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/kaffeinepart.cpp58
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/kaffeinepart.h222
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/mrl.cpp47
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/mrl.h96
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/playlistimport.cpp685
-rw-r--r--kaffeine/src/player-parts/kaffeine-part/playlistimport.h50
7 files changed, 1170 insertions, 0 deletions
diff --git a/kaffeine/src/player-parts/kaffeine-part/Makefile.am b/kaffeine/src/player-parts/kaffeine-part/Makefile.am
new file mode 100644
index 0000000..7202c10
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/Makefile.am
@@ -0,0 +1,12 @@
+lib_LTLIBRARIES = libkaffeinepart.la
+
+INCLUDES = $(all_includes)
+
+kaffeineincludedir = $(includedir)/kaffeine
+kaffeineinclude_HEADERS = kaffeinepart.h mrl.h
+
+METASOURCES = AUTO
+
+libkaffeinepart_la_SOURCES = kaffeinepart.cpp mrl.cpp playlistimport.cpp
+libkaffeinepart_la_LIBADD = $(LIB_KPARTS) $(all_libraries)
+libkaffeinepart_la_LDFLAGS = -no-undefined -avoid-version
diff --git a/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.cpp b/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.cpp
new file mode 100644
index 0000000..4be8b73
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.cpp
@@ -0,0 +1,58 @@
+/*
+ * kaffeinepart.cpp
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "kaffeinepart.h"
+#include <kapplication.h>
+#include <kservice.h>
+#include <ktrader.h>
+#include <kmessagebox.h>
+#include <krun.h>
+#include <klocale.h>
+
+#include "kaffeinepart.moc"
+
+KaffeinePart::KaffeinePart(QObject* parent, const char* name)
+ : KParts::ReadOnlyPart(parent, name)
+{
+}
+
+KaffeinePart::~KaffeinePart()
+{
+}
+
+bool KaffeinePart::installDistroCodec(QWidget* parent, const QString& engine, const QString& codec)
+{
+ QString query = QString("[X-KDE-Kaffeine-codec] == '%1' and \
+ [X-KDE-Kaffeine-engine] == '%2'").arg(codec).arg(engine);
+
+ KService::Ptr service = KTrader::self()->query( "Kaffeine/CodecInstall", query).first();
+
+ if (!service)
+ return false;
+
+ QString installScript = service->exec();
+
+ if (installScript.isNull())
+ return false;
+
+ KRun::runCommand(installScript);
+ return true;
+}
+
diff --git a/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.h b/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.h
new file mode 100644
index 0000000..e569ead
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/kaffeinepart.h
@@ -0,0 +1,222 @@
+/*
+ * kaffeinepart.h
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEPART_H
+#define KAFFEINEPART_H
+
+#include <kparts/part.h>
+
+#include "mrl.h"
+
+/*
+ * Base-Class for Kaffeine-Parts. Derive from this class if you want to develop a player part for Kaffeine.
+ * At least you have to reimplement openURL(const MRL&) and to emit signalTrackFinished()!
+ *
+ * IMPORTANT: Forward the double-click, middle-click and wheel mouse-events to the parent widget (don't use
+ * QMouseEvent::accept())!
+ *
+ * @author Jürgen Kofler
+ */
+
+class KDE_EXPORT KaffeinePart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+public:
+ KaffeinePart(QObject* parent, const char* name);
+ virtual ~KaffeinePart();
+
+ /*
+ * Playback in progress?
+ */
+ virtual bool isPlaying()
+ {
+ return false;
+ }
+
+ /*
+ * Playback paused?
+ */
+ virtual bool isPaused()
+ {
+ return false;
+ }
+
+ /*
+ * Should look like "*.mp3 *.MP3 *.avi *.AVI", used as file filter for directory import
+ */
+ virtual QString supportedExtensions()
+ {
+ return QString::null;
+ }
+
+ /*
+ * Current volume. In percent.
+ */
+ virtual uint volume() const
+ {
+ return 0;
+ }
+ /*
+ * Current position. In percent.
+ */
+ virtual uint position() const
+ {
+ return 0;
+ }
+
+ /*
+ * DVD etc.
+ */
+ virtual bool hasChapters()
+ {
+ return false;
+ }
+
+ virtual void setDVDChapter(uint) {}
+
+ /*
+ * Contain the stream video?
+ */
+ virtual bool hasVideo()
+ {
+ return false;
+ }
+
+signals:
+ /*
+ * Frame size of video changed
+ */
+ void signalNewFrameSize(const QSize& frame);
+
+ /*
+ * New meta information available
+ */
+ void signalNewMeta(const MRL &mrl);
+
+ /*
+ * Playback of current track finished
+ */
+ void signalTrackFinished();
+
+ /*
+ * Playback failed
+ */
+ void signalPlaybackFailed();
+
+ /*
+ * User pressed play button but queue is empty
+ */
+ void signalRequestCurrentTrack();
+
+ /*
+ * User pressed next button but no track left in queue
+ */
+ void signalRequestNextTrack();
+
+ /*
+ * User pressed previous button but queue is empty
+ */
+ void signalRequestPreviousTrack();
+
+ void signalToggleMinimalMode();
+
+public slots:
+ /*
+ * You have to reimplement this! Opens an url and plays it.
+ */
+ virtual bool openURL(const MRL &mrl) = 0;
+
+ /*
+ * Tells the player we go fullscreen now. Hide controls etc.
+ */
+ virtual void slotPrepareForFullscreen(bool)
+ {}
+
+ /*
+ * DVD etc.
+ */
+ virtual void playNextChapter()
+ {}
+
+ /*
+ * DVD etc.
+ */
+ virtual void playPreviousChapter()
+ {}
+
+ /*
+ * Toggle play/pause
+ */
+ virtual void slotTogglePause(bool pauseLive = true)
+ {
+ pauseLive = true;
+ }
+
+ /*
+ * Stop playback
+ */
+ virtual void slotStop()
+ {}
+
+ /*
+ * Sets Volume. In percent.
+ */
+ virtual void slotSetVolume(uint)
+ {}
+
+ /*
+ * Sets Position. In percent.
+ */
+ virtual void slotSetPosition(uint)
+ {}
+
+ virtual void slotPosPlusSmall()
+ {}
+
+ virtual void slotPosMinusSmall()
+ {}
+
+ /*
+ * Turn mute on/off
+ */
+ virtual void slotMute()
+ {}
+
+ /*
+ * Execute distro-dependent actions to install codecs
+ */
+ static bool installDistroCodec(QWidget* parent, const QString& engine, const QString& codec);
+
+private:
+ /*
+ * Don't reimplement this, a player should be able to stream media
+ */
+ bool openFile()
+ {
+ return false;
+ }
+
+ bool openURL(const KURL &url)
+ {
+ return openURL(MRL(url));
+ }
+};
+
+#endif /* KAFFEINEPART_H */
diff --git a/kaffeine/src/player-parts/kaffeine-part/mrl.cpp b/kaffeine/src/player-parts/kaffeine-part/mrl.cpp
new file mode 100644
index 0000000..9ab6e52
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/mrl.cpp
@@ -0,0 +1,47 @@
+/*
+ * mrl.cpp
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "mrl.h"
+
+MRL::MRL()
+{
+ reset();
+}
+
+MRL::MRL(const KURL& url, const QString& title, const QTime& length, const QString& mime,
+ const QString& artist, const QString& album, const QString& track,
+ const QString& year, const QString& genre, const QString& comment,
+ const QStringList& subtitleFiles, const int currentSubtitle) :
+ m_url(url.prettyURL()), m_kurl(url), m_title(title), m_artist(artist), m_album(album), m_track(track), m_year(year), m_genre(genre), m_comment(comment),
+ m_mime(mime), m_length(length), m_subtitleFiles(subtitleFiles), m_currentSubtitle(currentSubtitle)
+{}
+
+MRL::MRL(const QString& url, const QString& title, const QTime& length, const QString& mime,
+ const QString& artist, const QString& album, const QString& track,
+ const QString& year, const QString& genre, const QString& comment,
+ const QStringList& subtitleFiles, const int currentSubtitle) :
+ m_url(url), m_kurl(KURL::fromPathOrURL(url)), m_title(title), m_artist(artist),
+ m_album(album), m_track(track), m_year(year), m_genre(genre), m_comment(comment),
+ m_mime(mime), m_length(length), m_subtitleFiles(subtitleFiles), m_currentSubtitle(currentSubtitle)
+{}
+
+MRL::~MRL()
+{
+}
diff --git a/kaffeine/src/player-parts/kaffeine-part/mrl.h b/kaffeine/src/player-parts/kaffeine-part/mrl.h
new file mode 100644
index 0000000..04c6d27
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/mrl.h
@@ -0,0 +1,96 @@
+/*
+ * mrl.h
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef MRL_H
+#define MRL_H
+
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+
+/*
+ * media resource locator
+ * holds url and meta info
+ */
+
+class KDE_EXPORT MRL
+{
+public:
+ MRL();
+ /* don't use this constructor to prevent encoding problems */
+ MRL(const KURL& url, const QString& title = QString::null, const QTime& length = QTime(), const QString& mime = QString::null,
+ const QString& artist = QString::null, const QString& album = QString::null, const QString& track = QString::null,
+ const QString& year = QString::null, const QString& genre = QString::null, const QString& comment = QString::null,
+ const QStringList& subtitleFiles = QStringList(), const int currentSubtitle = -1);
+ MRL(const QString& url, const QString& title = QString::null, const QTime& length = QTime(), const QString& mime = QString::null,
+ const QString& artist = QString::null, const QString& album = QString::null, const QString& track = QString::null,
+ const QString& year = QString::null, const QString& genre = QString::null, const QString& comment = QString::null,
+ const QStringList& subtitleFiles = QStringList(), const int currentSubtitle = -1);
+ virtual ~MRL();
+
+ void reset() { m_url = QString::null; m_kurl = KURL(); }
+ bool isEmpty() { return (m_url == QString::null); }
+
+ const QString& url() const { return m_url; }
+ const KURL& kurl() const { return m_kurl; }
+ const QString& title() const { return m_title; }
+ const QString& artist() const { return m_artist; }
+ const QString& album() const { return m_album; }
+ const QString& track() const { return m_track; }
+ const QString& year() const { return m_year; }
+ const QString& genre() const { return m_genre; }
+ const QString& comment() const { return m_comment; }
+ const QString& mime() const { return m_mime; }
+ const QTime& length() const { return m_length; }
+ const QStringList& subtitleFiles() const { return m_subtitleFiles; }
+ int currentSubtitle() const { return m_currentSubtitle; }
+
+ void setURL(const QString& url) { m_url = url; m_kurl = KURL(url); }
+ void setTitle(const QString& title) { m_title = title; }
+ void setArtist(const QString& artist) { m_artist = artist; }
+ void setAlbum(const QString& album) { m_album = album; }
+ void setTrack(const QString& track) { m_track = track; }
+ void setYear(const QString& year) { m_year = year; }
+ void setGenre(const QString& genre) { m_genre = genre; }
+ void setComment(const QString& comment) { m_comment = comment; }
+ void setMime(const QString& mime) { m_mime = mime; }
+ void setLength(const QTime& length) { m_length = length; }
+ void setSubtitleFiles(const QStringList& urls) { m_subtitleFiles = urls; }
+ void addSubtitleFile(const QString& url) { m_subtitleFiles.append(url); }
+ void setCurrentSubtitle(int sub) { m_currentSubtitle = sub; }
+
+private:
+ QString m_url;
+ KURL m_kurl;
+ QString m_title;
+ QString m_artist;
+ QString m_album;
+ QString m_track;
+ QString m_year;
+ QString m_genre;
+ QString m_comment;
+ QString m_mime;
+ QTime m_length;
+ QStringList m_subtitleFiles;
+ int m_currentSubtitle; /* -1 -> off */
+};
+
+#endif /* MRL_H */
diff --git a/kaffeine/src/player-parts/kaffeine-part/playlistimport.cpp b/kaffeine/src/player-parts/kaffeine-part/playlistimport.cpp
new file mode 100644
index 0000000..13b5d63
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/playlistimport.cpp
@@ -0,0 +1,685 @@
+/*
+ * playlistimport.cpp
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qdom.h>
+#include <qregexp.h>
+#include <qxml.h>
+
+#include <kdebug.h>
+#include <kio/netaccess.h>
+
+#include "playlistimport.h"
+
+class MyXMLParser : public QXmlDefaultHandler
+{
+
+public:
+ QValueList<MRL> mrls;
+ bool isKaffeinePlaylist;
+
+
+ MyXMLParser() : isKaffeinePlaylist(false)
+ {}
+
+ bool startElement(const QString&, const QString&,
+ const QString &qname, const QXmlAttributes &att)
+ {
+
+ if (qname == "playlist")
+ if (att.value("client") == "kaffeine")
+ {
+ isKaffeinePlaylist = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ if (qname != "entry") return true;
+
+ QStringList subs = QStringList();
+ int currentSub = -1;
+
+ if ((!att.value("subs").isNull()) && (!att.value("subs").isEmpty()))
+ subs = QStringList::split("&",att.value("subs"),false);
+ if ((!att.value("subs").isNull()) && (!att.value("subs").isEmpty()))
+ {
+ bool ok;
+ currentSub = att.value("currentSub").toInt(&ok);
+ if (!ok)
+ currentSub = -1;
+ }
+
+ // kdDebug() << "PlaylistImport: kaffeine import url: " << att.value("url") << endl;
+ mrls.append(MRL(att.value("url"), att.value("title"), PlaylistImport::stringToTime(att.value("length")),
+ att.value("mime"), att.value("artist"), att.value("album"), att.value("track"),
+ att.value("year"), att.value("genre"), QString::null, subs, currentSub));
+ return true;
+ }
+
+};
+
+bool PlaylistImport::kaffeine(const QString& playlist, QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: kaffeine: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+
+ QXmlInputSource source(&file);
+ QXmlSimpleReader reader;
+
+ MyXMLParser parser;
+ reader.setContentHandler(&parser);
+ reader.parse(source);
+ file.close();
+
+ if (!parser.isKaffeinePlaylist)
+ {
+ return false;
+ }
+ else
+ {
+ QValueList<MRL>::ConstIterator end(parser.mrls.end());
+ for (QValueList<MRL>::ConstIterator it = parser.mrls.begin(); it != end; ++it)
+ mrls.append(*it);
+ return true;
+ }
+}
+
+class NoatunXMLParser : public QXmlDefaultHandler
+{
+
+public:
+ QValueList<MRL> mrls;
+ bool isNoatunPlaylist;
+
+ NoatunXMLParser(): isNoatunPlaylist(false)
+ {}
+
+ bool startElement(const QString&, const QString &,
+ const QString &qname, const QXmlAttributes &att)
+ {
+
+ if (qname == "playlist")
+ if (att.value("client") == "noatun")
+ {
+ isNoatunPlaylist = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ if (qname != "item") return true;
+
+ QString title = att.value("title");
+
+ if (title.isNull())
+ title = att.value("url");
+
+ bool ok;
+ QTime length;
+ int time = att.value("length").toInt(&ok);
+ if ((ok) && (time > 0))
+ {
+ length = QTime().addMSecs(time);
+ }
+
+ kdDebug() << "PlaylistImport: noatun import url: " << att.value("url") << endl;
+ mrls.append(MRL(att.value("url"), title, length, QString::null, att.value("author"),
+ att.value("album"), att.value("track")));
+
+ return true;
+ }
+
+};
+
+bool PlaylistImport::noatun(const QString& playlist, QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: noatun: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+
+ QXmlInputSource source(&file);
+ QXmlSimpleReader reader;
+
+ NoatunXMLParser parser;
+ reader.setContentHandler(&parser);
+ reader.parse(source);
+ file.close();
+
+ if (!parser.isNoatunPlaylist)
+ {
+ return false;
+ }
+ else
+ {
+ QValueList<MRL>::ConstIterator end(parser.mrls.end());
+ for (QValueList<MRL>::ConstIterator it = parser.mrls.begin(); it != end; ++it)
+ mrls.append(*it);
+ return true;
+ }
+}
+
+bool PlaylistImport::m3u(const QString& playlist , QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: m3u: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+ QTextStream stream(&file);
+
+ // if (stream.readLine().upper() != "#EXTM3U") return false;
+ QString url;
+ int time;
+ bool ok;
+ QTime length;
+ QString title;
+ KURL kUrl;
+ bool foundAnyUrl = false;
+ KURL plurl(playlist);
+ plurl.setFileName ("");
+
+ while (!stream.eof())
+ {
+ url = stream.readLine();
+ time = 0;
+ title = QString::null;
+ length = QTime();
+ if (url.left(1) == "#")
+ {
+ if (url.left(7).upper() == "#EXTINF")
+ {
+ url = url.remove(0,8);
+ time = url.section(",", 0,0).toInt(&ok);
+ if ((ok) && (time > 0))
+ {
+ length = QTime().addSecs(time);
+ }
+
+ title = url.section(",",1,1);
+ url = stream.readLine();
+ }
+ else
+ {
+ continue;
+ }
+ }
+ url.replace ('\\', '/'); /* for windows styled urls */
+ kUrl = KURL (plurl, url); /* maybe a relative url */
+ if (kUrl.isValid())
+ {
+ kdDebug() << "PlaylistImport: m3u import url: " << kUrl.prettyURL() << endl;
+
+ MRL mrl;
+ if (kUrl.isLocalFile())
+ mrl.setURL(kUrl.path());
+ else
+ mrl.setURL(kUrl.prettyURL());
+ if (title.isNull())
+ title = kUrl.fileName();
+ mrl.setTitle(title);
+ mrl.setLength(length);
+
+ mrls.append(mrl);
+
+ foundAnyUrl = true;
+ }
+ else
+ kdDebug() << "PlaylistImport: M3U: Not valid: " << kUrl.prettyURL() << endl;
+ }
+ file.close();
+ if (foundAnyUrl)
+ return true;
+ else
+ return false;
+}
+
+bool PlaylistImport::pls(const QString& playlist, QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: pls: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+
+ QTextStream stream(&file);
+
+ //if (stream.readLine().upper() != "[PLAYLIST]") return false;
+
+ // Better Handling of pls playlists - Taken from amaroK - amarok.kde.org
+ // Counted number of "File#=" lines.
+ uint entryCnt = 0;
+ // Value of the "NumberOfEntries=#" line.
+ uint numberOfEntries = 0;
+ bool havePlaylistSection = false;
+ QString tmp;
+ QStringList lines;
+
+ // set Regexp keywords, Be case insensitive
+ const QRegExp regExp_NumberOfEntries("^NumberOfEntries\\s*=\\s*\\d+$", false);
+ const QRegExp regExp_File("^File\\d+\\s*=", false);
+ const QRegExp regExp_Title("^Title\\d+\\s*=", false);
+ const QRegExp regExp_Length("^Length\\d+\\s*=\\s*-?\\d+$", false);
+ const QRegExp regExp_Version("^Version\\s*=\\s*\\d+$", false);
+ const QString section_playlist("[playlist]");
+
+ /* Preprocess the input data.
+ * Read the lines into a buffer; Cleanup the line strings;
+ * Count the entries manually and read "NumberOfEntries".
+ */
+ while (!stream.atEnd()) {
+ tmp = stream.readLine();
+ tmp = tmp.stripWhiteSpace();
+ if (tmp.isEmpty())
+ continue;
+ lines.append(tmp);
+
+ if (tmp == section_playlist) {
+ havePlaylistSection = true;
+ continue;
+ }
+
+ if (tmp.contains(regExp_File)) {
+ entryCnt++;
+ continue;
+ }
+
+ if (tmp.contains(regExp_NumberOfEntries)) {
+ numberOfEntries = tmp.section('=', -1).stripWhiteSpace().toUInt();
+ continue;
+ }
+ }
+
+ file.close();
+
+ if (numberOfEntries != entryCnt) {
+ kdError() << "PlaylistImport: Invalid \"NumberOfEntries\" value in .pls playlist. "
+ << "NumberOfEntries=" << numberOfEntries << " counted="
+ << entryCnt << endl;
+ /* Corrupt file. The "NumberOfEntries" value is
+ * not correct. Fix it by setting it to the manually
+ * counted number and go on parsing.
+ */
+ numberOfEntries = entryCnt;
+ }
+ // If we have no Entries, return
+ if (!numberOfEntries)
+ return true;
+
+ int time;
+ bool ok;
+ uint index;
+ bool inPlaylistSection = false;
+ QString* titles = new QString[entryCnt];
+ QString* files = new QString[entryCnt];
+ QTime* length = new QTime[entryCnt];
+
+ QStringList::const_iterator i = lines.begin(), end = lines.end();
+ for ( ; i != end; ++i) {
+ if (!inPlaylistSection && havePlaylistSection) {
+ /* The playlist begins with the "[playlist]" tag.
+ * Skip everything before this.
+ */
+ if ((*i) == section_playlist)
+ inPlaylistSection = true;
+ continue;
+ }
+ if ((*i).contains(regExp_File)) {
+ // Have a "File#=XYZ" line.
+ index = extractIndex(*i);
+ if (index > numberOfEntries || index == 0)
+ continue;
+ files[index-1] = (*i).section('=', 1).stripWhiteSpace();
+ continue;
+ }
+ if ((*i).contains(regExp_Title)) {
+ // Have a "Title#=XYZ" line.
+ index = extractIndex(*i);
+ if (index > numberOfEntries || index == 0)
+ continue;
+ titles[index-1] = (*i).section('=', 1).stripWhiteSpace();
+ continue;
+ }
+ if ((*i).contains(regExp_Length)) {
+ // Have a "Length#=XYZ" line.
+ index = extractIndex(*i);
+ if (index > numberOfEntries || index == 0)
+ continue;
+ tmp = (*i).section('=', 1).stripWhiteSpace();
+ time = tmp.toInt(&ok);
+ if ( !(ok) || !(time > 0) ) continue;
+ length[index-1] = QTime().addSecs(time);
+ continue;
+ }
+ if ((*i).contains(regExp_NumberOfEntries)) {
+ // Have the "NumberOfEntries=#" line.
+ continue;
+ }
+ if ((*i).contains(regExp_Version)) {
+ // Have the "Version=#" line.
+ tmp = (*i).section('=', 1).stripWhiteSpace();
+ // We only support Version=2
+ if (tmp.toUInt(&ok) != 2)
+ kdWarning() << "PlaylistImport: pls: Unsupported version." << endl;
+ continue;
+ }
+ kdWarning() << "PlaylistImport: pls: Unrecognized line: \"" << *i << "\"" << endl;
+ }
+
+ for (uint i=0; i<entryCnt; i++)
+ {
+ if (files[i].isNull()) continue;
+ kdDebug() << "PlaylistImport: pls import url: " << files[i] << endl;
+ if (titles[i].isNull())
+ titles[i] = files[i];
+ mrls.append(MRL(files[i], titles[i], length[i]));
+ }
+
+ delete [] titles;
+ delete [] files;
+ delete [] length;
+
+ return true;
+}
+
+// Helper for pls import
+uint PlaylistImport::extractIndex( const QString &str )
+{
+ /* Extract the index number out of a .pls line.
+ * Example:
+ * extractIndex("File2=foobar") == 2
+ */
+ bool ok = false;
+ unsigned int ret;
+ QString tmp(str.section('=', 0, 0));
+ tmp.remove(QRegExp("^\\D*"));
+ ret = tmp.stripWhiteSpace().toUInt(&ok);
+ if (!ok)
+ kdError() << "PlaylistImport: pls: Corrupt pls file, Error extracting index." << endl;
+ return ret;
+}
+
+bool PlaylistImport::ram(const MRL& playlist, QValueList<MRL>& mrls, QWidget* parent)
+{
+ Q_ULONG result;
+ char buf[10];
+
+ kdDebug() << "PlaylistImport: ram: " << playlist.url() << endl;
+ memset( buf, 0, 10 );
+
+ if (playlist.kurl().isLocalFile()) {
+ QFile file(playlist.kurl().path());
+ if (!file.open(IO_ReadOnly)) {
+ kdError() << "PlaylistImport: Can't open " << playlist.url() << endl;
+ return false;
+ }
+ result = file.readBlock(buf, 4);
+ file.close();
+ if (result != 4) {
+ kdError() << "PlaylistImport: Can't read " << playlist.url() << endl;
+ return false;
+ }
+ if (buf[0]=='.' && buf[1]=='R' && buf[2]=='M' && buf[3]=='F') {
+ kdDebug() << "PlaylistImport: Seems to be a real media file" << endl;
+ return false;
+ }
+ }
+ else if (!playlist.kurl().protocol().startsWith("http")) {
+ kdError() << "PlaylistImport: ram: Download via " << playlist.kurl().protocol() << " protocol not supported." << endl;
+ return false;
+ }
+
+ kdDebug() << "PlaylistImport: Seems to be a ram playlist!" << endl;
+
+ QString localFile, url;
+ if (KIO::NetAccess::mimetype(playlist.kurl(), parent) == "application/vnd.rn-realmedia") {
+ kdDebug() << "PlaylistImport: Seems to be a real media file" << endl;
+ return false;
+ }
+
+ if (KIO::NetAccess::download(playlist.kurl(), localFile, parent))
+ {
+ QFile plFile(localFile);
+ if (!plFile.open(IO_ReadOnly)) return false;
+ QTextStream stream( &plFile );
+
+ while (!stream.eof())
+ {
+ url = stream.readLine();
+
+ if (url[0] == '#') continue; /* ignore comments */
+ if (url == "--stop--") break; /* stop line */
+
+ if ((url.left(7) == "rtsp://") || (url.left(6) == "pnm://") || (url.left(7) == "http://"))
+ {
+ kdDebug() << "PlaylistImport: ram import url: " << url << endl;
+ mrls.append(MRL(url, url));
+ }
+ }
+ }
+ else {
+ kdError() << "PlaylistImport: " << KIO::NetAccess::lastErrorString() << endl;
+ return false;
+ }
+
+ return true;
+}
+
+/**********************************************************************************
+ * load asx playlist *
+ * spec: http://msdn.microsoft.com/library/en-us/wmplay/mmp_sdk/asxelement.asp *
+ **********************************************************************************/
+
+bool PlaylistImport::asx(const QString& playlist, QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: asx: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorLine, errorColumn;
+ if (!doc.setContent(&file, &errorMsg, &errorLine, &errorColumn))
+ {
+ kdError() << "PlaylistImport: XML parse error: " << errorMsg
+ << " (line: " << errorLine << ", column: " << errorColumn << ")" << endl;
+ return false;
+ }
+
+ QDomElement root = doc.documentElement();
+
+ QString url;
+ QString title;
+ QString author;
+ QTime length;
+ QString duration;
+
+ if (root.nodeName().lower() != "asx") return false;
+
+ QDomNode node = root.firstChild();
+ QDomNode subNode;
+ QDomElement element;
+
+ while (!node.isNull())
+ {
+ url = QString::null;
+ title = QString::null;
+ author = QString::null;
+ length = QTime();
+ if (node.nodeName().lower() == "entry")
+ {
+ subNode = node.firstChild();
+ while (!subNode.isNull())
+ {
+ if ((subNode.nodeName().lower() == "ref") && (subNode.isElement()) && (url.isNull()))
+ {
+ element = subNode.toElement();
+ if (element.hasAttribute("href"))
+ url = element.attribute("href");
+ if (element.hasAttribute("HREF"))
+ url = element.attribute("HREF");
+ if (element.hasAttribute("Href"))
+ url = element.attribute("Href");
+ if (element.hasAttribute("HRef"))
+ url = element.attribute("HRef");
+
+ }
+
+ if ((subNode.nodeName().lower() == "duration") && (subNode.isElement()))
+ {
+ duration = QString::null;
+ element = subNode.toElement();
+ if (element.hasAttribute("value"))
+ duration = element.attribute("value");
+ if (element.hasAttribute("Value"))
+ duration = element.attribute("Value");
+ if (element.hasAttribute("VALUE"))
+ duration = element.attribute("VALUE");
+
+ if (!duration.isNull())
+ length = PlaylistImport::stringToTime(duration);
+ }
+
+ if ((subNode.nodeName().lower() == "title") && (subNode.isElement()))
+ {
+ title = subNode.toElement().text();
+ }
+ if ((subNode.nodeName().lower() == "author") && (subNode.isElement()))
+ {
+ author = subNode.toElement().text();
+ }
+
+ /* possible nodes we ignore: ABSTRACT, BANNER, BASE, COPYRIGHT, ENDMARKER, MOREINFO, PARAM,
+ * PREVIEWDURATION, STARTMARKER, STARTTIME
+ */
+ subNode = subNode.nextSibling();
+ }
+
+ if (!url.isNull())
+ {
+ if (title.isNull())
+ title = url;
+ kdDebug() << "PlaylistImport: asx import url: " << url << endl;
+ mrls.append(MRL(url, title, length, QString::null, author));
+ }
+ }
+ node = node.nextSibling();
+ }
+
+ file.close();
+
+ return true;
+}
+
+/****************************************************************
+ * Full SMIL support seems to be impossible at the moment... *
+ * spec: http://www.w3.org/TR/REC-smil/ *
+ ****************************************************************/
+
+bool PlaylistImport::smil(const QString& playlist, const MRL& baseMRL, QValueList<MRL>& mrls)
+{
+ kdDebug() << "PlaylistImport: smil: " << playlist << endl;
+ QFile file(playlist);
+ if (!file.open(IO_ReadOnly)) return false;
+
+ QDomDocument doc;
+ doc.setContent(&file);
+ QDomElement root = doc.documentElement();
+
+ if (root.nodeName().lower() != "smil") return false;
+
+ bool anyURL = false;
+ KURL kurl;
+ QString url;
+ QDomNodeList nodeList;
+ QDomNode node;
+ QDomElement element;
+
+ //video sources...
+ nodeList = doc.elementsByTagName("video");
+ kdDebug() << "PlaylistImport: smil: " << nodeList.count() << " 'video' tags found" << endl;
+ for (uint i = 0; i < nodeList.count(); i++)
+ {
+ node = nodeList.item(i);
+ url = QString::null;
+ if ((node.nodeName().lower() == "video") && (node.isElement()))
+ {
+ element = node.toElement();
+ if (element.hasAttribute("src"))
+ url = element.attribute("src");
+ if (element.hasAttribute("Src"))
+ url = element.attribute("Src");
+ if (element.hasAttribute("SRC"))
+ url = element.attribute("SRC");
+ }
+ if (!url.isNull())
+ {
+ kurl = KURL(baseMRL.kurl(), url);
+ kdDebug() << "PlaylistImport: smil: found video source: " << kurl.url() << endl;
+ mrls.append(kurl);
+ anyURL = true;
+ }
+ }
+
+ //audio sources...
+ nodeList = doc.elementsByTagName("audio");
+ kdDebug() << "PlaylistImport: smil: " << nodeList.count() << " 'audio' tags found" << endl;
+ for (uint i = 0; i < nodeList.count(); i++)
+ {
+ node = nodeList.item(i);
+ url = QString::null;
+ if ((node.nodeName().lower() == "audio") && (node.isElement()))
+ {
+ element = node.toElement();
+ if (element.hasAttribute("src"))
+ url = element.attribute("src");
+ if (element.hasAttribute("Src"))
+ url = element.attribute("Src");
+ if (element.hasAttribute("SRC"))
+ url = element.attribute("SRC");
+ }
+ if (!url.isNull())
+ {
+ kurl = KURL(baseMRL.kurl(), url);
+ kdDebug() << "PlaylistImport: smil: found audio source: " << kurl.url() << endl;
+ mrls.append(kurl);
+ anyURL = true;
+ }
+ }
+
+ file.close();
+ return anyURL;
+}
+
+QTime PlaylistImport::stringToTime(const QString& timeString)
+{
+ int sec = 0;
+ bool ok = false;
+ QStringList tokens = QStringList::split(':',timeString);
+
+ sec += tokens[0].toInt(&ok)*3600; //hours
+ sec += tokens[1].toInt(&ok)*60; //minutes
+ sec += tokens[2].toInt(&ok); //secs
+
+ if (ok)
+ return QTime().addSecs(sec);
+ else
+ return QTime();
+}
diff --git a/kaffeine/src/player-parts/kaffeine-part/playlistimport.h b/kaffeine/src/player-parts/kaffeine-part/playlistimport.h
new file mode 100644
index 0000000..16420eb
--- /dev/null
+++ b/kaffeine/src/player-parts/kaffeine-part/playlistimport.h
@@ -0,0 +1,50 @@
+/*
+ * playlistimport.h
+ *
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PLAYLISTIMPORT_H
+#define PLAYLISTIMPORT_H
+
+#include "mrl.h"
+
+class QWidget;
+
+/*
+ * static methods for playlist import
+ */
+
+class KDE_EXPORT PlaylistImport
+{
+public:
+
+ static bool kaffeine(const QString&, QValueList<MRL>&);
+ static bool noatun(const QString&, QValueList<MRL>&);
+ static bool m3u(const QString&, QValueList<MRL>&);
+ static bool pls(const QString&, QValueList<MRL>&);
+ static bool ram(const MRL&, QValueList<MRL>&, QWidget*);
+ static bool asx(const QString&, QValueList<MRL>&);
+ static bool smil(const QString&, const MRL&, QValueList<MRL>&);
+ /* helper */
+ static QTime stringToTime(const QString&);
+
+private:
+ static uint extractIndex(const QString&);
+};
+
+#endif /* PLAYLISTIMPORT_H */