MythTV  master
pls.cpp
Go to the documentation of this file.
1 /*
2  playlistfile (.pls) parser
3  Eskil Heyn Olsen, 2005, distributed under the GPL as part of mythtv.
4 
5  Update July 2010 updated for Qt4 (Paul Harrison)
6  Update December 2012 updated to use QSettings for the pls parser
7  Update September 2014 add simple asx parser
8 */
9 
10 // c++
11 #include <string>
12 
13 // qt
14 #include <QDomDocument>
15 #include <QFileInfo>
16 #include <QList>
17 #include <QMap>
18 #include <QPair>
19 #include <QRegularExpression>
20 #include <QSettings>
21 #include <QStringList>
22 
23 // MythTV
25 
26 // mythmusic
27 #include "pls.h"
28 
30 {
31  clear();
32 }
33 
34 int PlayListFile::parse(PlayListFile *pls, const QString &filename)
35 {
36  int result = 0;
37  QString extension = QFileInfo(filename).suffix().toLower();
38 
39  if (extension == "pls")
40  result = PlayListFile::parsePLS(pls, filename);
41  else if (extension == "m3u")
42  result = PlayListFile::parseM3U(pls, filename);
43  else if (extension == "asx")
44  result = PlayListFile::parseASX(pls, filename);
45 
46  return result;
47 }
48 
49 int PlayListFile::parsePLS(PlayListFile *pls, const QString &filename)
50 {
51  LOG(VB_FILE, LOG_DEBUG, QString("DecoderHandler: parsePLS - '%1'").arg(filename));
52 
53  QSettings settings(filename, QSettings::IniFormat);
54 
55  // we allow both 'playlist' and 'Playlist' for the group name
56  QStringList groups = settings.childGroups();
57 
58  if (groups.contains("playlist"))
59  settings.beginGroup("playlist");
60  else if (groups.contains("Playlist"))
61  settings.beginGroup("Playlist");
62  else
63  {
64  LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler: parsePLS - playlist group not found"));
65  return 0;
66  }
67 
68  int num_entries = -1;
69 
70  // Some pls files have "numberofentries", some have "NumberOfEntries".
71  QStringList keys = settings.childKeys();
72 
73  if (keys.contains("numberofentries"))
74  num_entries = settings.value("numberofentries", -1).toInt();
75  else if (keys.contains("NumberOfEntries"))
76  num_entries = settings.value("NumberOfEntries", -1).toInt();
77  else
78  {
79  LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler: parsePLS - NumberOfEntries key not found"));
80  return 0;
81  }
82 
83  for (int n = 1; n <= num_entries; n++)
84  {
85  auto *e = new PlayListFileEntry();
86  QString t_key = QString("Title%1").arg(n);
87  QString f_key = QString("File%1").arg(n);
88  QString l_key = QString("Length%1").arg(n);
89 
90  e->setFile(settings.value(f_key).toString());
91  e->setTitle(settings.value(t_key).toString());
92  e->setLength(settings.value(l_key).toInt());
93 
94  pls->add(e);
95  }
96 
97  return pls->size();
98 }
99 
100 static constexpr const char* M3U_HEADER { "#EXTM3U" };
101 static constexpr const char* M3U_INFO { "#EXTINF" };
102 
104 {
105  QFile f(filename);
106  if (!f.open(QIODevice::ReadOnly))
107  return 0;
108 
109  QTextStream stream(&f);
110  QString data = stream.readAll();
111  static const QRegularExpression kNewlineRE { "\\R" }; // Any unicode newline
112  QStringList lines = data.split(kNewlineRE);
113 
114  QStringList::iterator it;
115  for (it = lines.begin(); it != lines.end(); ++it)
116  {
117  // ignore empty lines
118  if (it->isEmpty())
119  continue;
120 
121  // ignore the M3U header
122  if (it->startsWith(M3U_HEADER))
123  continue;
124 
125  // for now ignore M3U info lines
126  if (it->startsWith(M3U_INFO))
127  continue;
128 
129  // add to the playlist
130  auto *e = new PlayListFileEntry();
131  e->setFile(*it);
132  e->setTitle(*it);
133  e->setLength(-1);
134 
135  pls->add(e);
136  }
137 
138  return pls->size();
139 }
140 
142 {
143  QDomDocument doc("mydocument");
144  QFile file(filename);
145  if (!file.open(QIODevice::ReadOnly))
146  return 0;
147 
148  if (!doc.setContent(&file))
149  {
150  file.close();
151  return 0;
152  }
153  file.close();
154 
155  //QDomElement docElem = doc.documentElement();
156  QDomNodeList entryList = doc.elementsByTagName("Entry");
157  QString url;
158 
159  for (int x = 0; x < entryList.count(); x++)
160  {
161  QDomNode n = entryList.item(x);
162  QDomElement elem = n.toElement();
163  QDomNodeList refList = elem.elementsByTagName("ref");
164  for (int y = 0; y < refList.count(); y++)
165  {
166  QDomNode n2 = refList.item(y);
167  QDomElement elem2 = n2.toElement();
168  if (!elem2.isNull())
169  {
170  url = elem2.attribute("href");
171 
172  // add to the playlist
173  auto *e = new PlayListFileEntry();
174  e->setFile(url.replace("mms://", "mmsh://"));
175  e->setTitle(url.replace("mms://", "mmsh://"));
176  e->setLength(-1);
177 
178  pls->add(e);
179  }
180  }
181  }
182 
183  return pls->size();
184 }
pls.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
build_compdb.file
file
Definition: build_compdb.py:55
M3U_INFO
static constexpr const char * M3U_INFO
Definition: pls.cpp:101
PlayListFileEntry
Class for representing entries in a pls file.
Definition: pls.h:19
mythlogging.h
PlayListFile::parse
static int parse(PlayListFile *pls, const QString &filename)
Parse a pls, m3u or asx playlist file.
Definition: pls.cpp:34
PlayListFile::~PlayListFile
~PlayListFile(void)
Definition: pls.cpp:29
PlayListFile
Class for containing the info of a pls or m3u file.
Definition: pls.h:41
PlayListFile::size
int size(void) const
Get the number of entries in the pls file.
Definition: pls.h:54
PlayListFile::clear
void clear(void)
Clear out all the entries.
Definition: pls.h:83
PlayListFile::parseM3U
static int parseM3U(PlayListFile *pls, const QString &filename)
Parse a m3u file.
Definition: pls.cpp:103
M3U_HEADER
static constexpr const char * M3U_HEADER
Definition: pls.cpp:100
PlayListFile::parseASX
static int parseASX(PlayListFile *pls, const QString &filename)
Parse a asx file.
Definition: pls.cpp:141
PlayListFile::add
void add(PlayListFileEntry *e)
Add a entry to the playlist.
Definition: pls.h:80
PlayListFile::parsePLS
static int parsePLS(PlayListFile *pls, const QString &filename)
Parse a pls file.
Definition: pls.cpp:49
build_compdb.filename
filename
Definition: build_compdb.py:21