Logo Search packages:      
Sourcecode: kaffeine version File versions

playlistimport.cpp

/***************************************************************************
 *   Copyright (C) 2004-2005 by 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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
 /*
  * Last modified: $Date: 2005/02/02 10:08:26 $ by $Author: juergenk $
  */

#include <kdebug.h> 
#include <kio/netaccess.h>
 
#include <qstringlist.h>
#include <qstring.h>
#include <qxml.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qfile.h>

#include "mrl.h"
#include "http.h"

#include "playlistimport.h"

class MyXMLParser : public QXmlDefaultHandler
{

public:
  MRL::List 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, MRL::List& 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
  {  
    for (MRL::List::ConstIterator it = parser.mrls.begin(); it != parser.mrls.end(); it++)
      mrls.append(*it);
    return true;
  }
}

class NoatunXMLParser : public QXmlDefaultHandler
{

public:
  MRL::List 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, MRL::List& 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
  {  
    for (MRL::List::ConstIterator it = parser.mrls.begin(); it != parser.mrls.end(); it++)
      mrls.append(*it);
    return true;
  }
}

bool PlaylistImport::m3u(const QString& playlist , MRL::List& 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, MRL::List& 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;
  
  /* number of entries */
  bool ok;
  QString numEntries = stream.readLine().remove(0,16);
  int entries = 0;
  entries = numEntries.toInt(&ok);
  if (!(ok) || !(entries>0)) return false;

  QString* titles = new QString[entries];
  QString* files = new QString[entries];
  QTime* length = new QTime[entries];

  for (int i=0; i<entries; i++)
  {
    titles[i] = QString::null;
    files[i] = QString::null;
    length[i] = QTime();
  }  
  
  QString line;
  int num;
  int time;
  
  while (!stream.eof())
  {
    line = stream.readLine();
   
    if (line.left(4).lower() == "file")
    {
      line = line.remove(0,4);

      num = line.left(line.find("=")).toInt(&ok);
      if ((!ok) && (num>entries)) continue;

      files[num-1] = line.remove(0, line.find("=") + 1);

      continue;
    }

    if (line.left(5).lower() == "title")
    {
      line = line.remove(0,5);

      num = line.left(line.find("=")).toInt(&ok);
      if ((!ok) && (num>entries)) continue;

      titles[num-1] = line.remove(0, line.find("=") + 1);

      continue;
    }

    if (line.left(6).lower() == "length")
    {
      line = line.remove(0,6);

      num = line.left(line.find("=")).toInt(&ok);
      if ((!ok) && (num>entries)) continue;

      time = 0;
      time = line.remove(0, line.find("=") + 1).toInt(&ok);
      if ( !(ok) || !(time > 0) ) continue;

      length[num-1] = QTime().addSecs(time);
    }  
    
  }

  file.close();

  for (int i=0; i<entries; 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;
}

bool PlaylistImport::ram(const MRL& playlist, MRL::List& mrls, QWidget* parent)
{
  kdDebug() << "PlaylistImport: ram: " << playlist.url() << endl;
  Q_ULONG result;
  char buf[10];
  char mime[1024];
 
  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;
    }
  }
  else
  {
    if (playlist.kurl().protocol() == "http")
    {

      result = http_peek(playlist.url(), 4, buf, mime);

      if (result <= 0)
      {
        kdError() << "Can't open " << playlist.url() << endl;
        return false;
      }
    }
    else
    {
      kdWarning() << "PlaylistImport: ram: Download via " << playlist.kurl().protocol() << " protocol not supported." << 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;
  }

  kdDebug() << "PlaylistImport: Seems to be a ram playlist!" << endl;

  QString localFile, url;
  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 true;
}

/**********************************************************************************
 *                             load asx playlist                                  *
 *   spec: http://msdn.microsoft.com/library/en-us/wmplay/mmp_sdk/asxelement.asp  *
 **********************************************************************************/

bool PlaylistImport::asx(const QString& playlist, MRL::List& mrls)
{
  kdDebug() << "PlaylistImport: asx: " << playlist << endl;
  QFile file(playlist);
  if (!file.open(IO_ReadOnly)) return false;

  QDomDocument doc;
  doc.setContent(&file);
  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, MRL::List& 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 = doc.elementsByTagName("video");
  QDomNode node;
  QDomElement element;

  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;
    }   
  }
  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(); 
}


Generated by  Doxygen 1.6.0   Back to index