123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- #ifdef _WIN32
- #include <winsock2.h>
- #endif
- #include "metadata.h"
- #include "aolxml/aolxml.h"
- #include "filenameMetadata.h"
- #include "file/fileUtils.h"
- #include "stl/stringUtils.h"
- #include "services/stdServiceImpl.h"
- #include "streamData.h"
- using namespace std;
- using namespace stringUtil;
- using namespace uniString;
- metadata::metadata(const metadata &m)
- {
- copy(m);
- }
- metadata& metadata::operator=(const metadata &m)
- {
- copy(m);
- return *this;
- }
- void metadata::clear() throw()
- {
- for (keyValueMap_t::const_iterator i = m_keyValueMap.begin(); i != m_keyValueMap.end(); ++i)
- {
- delete (*i).second;
- }
- m_keyValueMap.clear();
- }
- void metadata::copy(const metadata &m) throw()
- {
- clear();
- for (keyValueMap_t::const_iterator i = m.m_keyValueMap.begin(); i != m.m_keyValueMap.end(); ++i)
- {
- if ((*i).second)
- {
- m_keyValueMap.insert(make_pair((*i).first,(*i).second->clone()));
- }
- }
- }
- metadata::~metadata() throw()
- {
- clear();
- }
- // remove all values for key
- void metadata::removeValue(const string &key) throw()
- {
- keyValueMap_t::iterator i = m_keyValueMap.find(key);
- while (i != m_keyValueMap.end())
- {
- delete (*i).second;
- m_keyValueMap.erase(i);
- i = m_keyValueMap.find(key);
- }
- }
- bool metadata::valueExists(const string &key) const throw()
- {
- return (m_keyValueMap.find(key) != m_keyValueMap.end());
- }
- //// only returns first one found
- const metadata::metaValue_base* metadata::getValue(const string &key) const throw()
- {
- keyValueMap_t::const_iterator i = m_keyValueMap.find(key);
- return (i == m_keyValueMap.end() ? 0 : (*i).second);
- }
- //// only returns first one found
- utf8 metadata::getValueAsString(const std::string &key) const throw()
- {
- static utf8 empty;
- const metaValue_base *mv = getValue(key);
- return (mv ? mv->toString() : empty);
- }
- void metadata::setValue(const string &key,metadata::metaValue_base *value) throw()
- {
- m_keyValueMap.insert(make_pair(key,value));
- }
- utf8 metadata::safeXML(const string &tag,const metaValue_base *m) throw()
- {
- static utf8 empty;
- if (!m) return empty;
- return m->toXML(tag);
- }
- utf8 metadata::safeString(const metaValue_base *m) throw()
- {
- static utf8 empty;
- if (!m) return empty;
- return m->toString();
- }
- bool metadata::noMeaningfulMetadata() const throw()
- {
- return (m_keyValueMap.find(NAME()) == m_keyValueMap.end());
- }
- bool metadata::get_replayGain(double &gain) const throw()
- {
- pair<keyValueMap_t::const_iterator,keyValueMap_t::const_iterator> mdrange = m_keyValueMap.equal_range("TXXX");
- for (keyValueMap_t::const_iterator i = mdrange.first; i != mdrange.second; ++i)
- {
- metadata::metaValue<ID3V2::userText_t> *md = dynamic_cast<metadata::metaValue<ID3V2::userText_t> *>((*i).second);
- if (md)
- {
- ID3V2::userText_t ut = md->value();
- if (ut.m_id == "replaygain_track_gain" || ut.m_id == "REPLAYGAIN_TRACK_GAIN")
- {
- gain = atof((const char *)ut.m_text.c_str());
- return true;
- }
- }
- }
- return false;
- }
- bool metadata::get_replayGain() const throw()
- {
- double g;
- return get_replayGain(g);
- }
- const utf8 METADATA("<metadata>");
- const utf8 E_METADATA("</metadata>");
- #ifdef XML_DEBUG
- static const utf8 EOL(eol());
- #else
- static const utf8 EOL("");
- #endif
- // new xml for shoutcast
- utf8 metadata::toXML() const throw()
- {
- utf8 o;
- o += "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + EOL;
- o += METADATA + EOL;
- for (keyValueMap_t::const_iterator i = m_keyValueMap.begin(); i != m_keyValueMap.end(); ++i)
- {
- o += safeXML((*i).first,(*i).second) + EOL;
- }
- o += E_METADATA + EOL;
- return o;
- }
- utf8 metadata::toXML_fromFilename(const uniFile::filenameType &filename,const uniFile::filenameType &url,const utf8 &pattern) throw()
- {
- utf8 o;
- o += "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + EOL;
- o += METADATA + EOL;
- bool patternWorked(false);
- try
- {
- filenameMetadata fm;
- fm.setPattern(pattern);
- fm.parse(filename);
- const std::map<uniString::utf8,uniString::utf8>&m = fm.getTokens();
- for (map<utf8,utf8>::const_iterator i = m.begin(); i != m.end(); ++i)
- {
- o += "<" + (*i).first + ">" + (*i).second.escapeXML() + "</" + (*i).first + ">" + EOL;
- }
- patternWorked = true;
- }
- catch(.../*const exception &ex*/)
- {
- }
- if (!patternWorked)
- {
- try
- {
- string str = string(filename.toANSI(true));
- utf8 song = asciiToUtf8(str);
- filenameMetadata fm;
- fm.setPattern(pattern);
- fm.parse(song);
- const std::map<uniString::utf8,uniString::utf8>&m = fm.getTokens();
- for (map<utf8,utf8>::const_iterator i = m.begin(); i != m.end(); ++i)
- {
- o += "<" + (*i).first + ">" + (*i).second.escapeXML() + "</" + (*i).first + ">" + EOL;
- }
- patternWorked = true;
- }
- catch(.../*const exception &ex*/)
- {
- //ELOG(string("[METADATA] Failure converting filename to metadata ") + ex.what());
- }
- }
- if (!patternWorked)
- {
- o += "<TIT2>";
- utf8 us = fileUtil::stripSuffix(filename);
- // remove path based on delimiter for Unix (/) Win32 (\) or MacOS (:)
- us = fileUtil::stripPath(us,utf8("/"));
- us = fileUtil::stripPath(us,utf8("\\"));
- us = fileUtil::stripPath(us,utf8(":"));
- o += us.escapeXML();
- o += "</TIT2>" + EOL;
- }
- if (!url.empty())
- {
- utf8 u = url;
- if ((u.find(utf8("://")) == utf8::npos) &&
- (u.find(utf8("&")) != 0) &&
- u.find(utf8("DNAS/streamart?sid=")) == utf8::npos &&
- u.find(utf8("DNAS/playingart?sid=")) == utf8::npos)
- {
- u = "http://" + u;
- }
- o += "<URL>" + u.escapeXML() + "</URL>" + EOL;
- }
- o += E_METADATA + EOL;
- return o;
- }
- utf8 metadata::toFixedString(const uniFile::filenameType &filename) throw()
- {
- utf8 o;
- bool patternWorked(false);
- try
- {
- filenameMetadata fm;
- fm.setPattern("%N");
- fm.parse(filename);
- const std::map<uniString::utf8,uniString::utf8>&m = fm.getTokens();
- for (map<utf8,utf8>::const_iterator i = m.begin(); i != m.end(); ++i)
- {
- o = (*i).second;
- }
- patternWorked = true;
- }
- catch(.../*const exception &ex*/)
- {
- }
- if (!patternWorked)
- {
- try
- {
- string str = string(filename.toANSI(true));
- utf8 song = asciiToUtf8(str);
- filenameMetadata fm;
- fm.setPattern("%N");
- fm.parse(song);
- const std::map<uniString::utf8,uniString::utf8>&m = fm.getTokens();
- for (map<utf8,utf8>::const_iterator i = m.begin(); i != m.end(); ++i)
- {
- o = (*i).second;
- }
- patternWorked = true;
- }
- catch(.../*const exception &ex*/)
- {
- //ELOG(string("[METADATA] Failure converting filename to metadata ") + ex.what());
- }
- }
- if (!patternWorked)
- {
- o = filename;
- }
- return o;
- }
- uniString::utf8 metadata::convert_3902_to_shoutcast1(const uniString::utf8 &d, const streamID_t id) throw (std::runtime_error)
- {
- utf8 o;
- aolxml::node *n = 0;
- try
- {
- n = aolxml::node::parse(d.hideAsString());
- utf8 artist = aolxml::subNodeText(n, "/metadata/" + ARTIST(), (utf8)"");
- utf8 name = aolxml::subNodeText(n, "/metadata/" + NAME(), (utf8)"");
- if (!artist.empty())
- {
- if (!o.empty())
- {
- o += " - ";
- }
- o += artist;
- }
- if (!name.empty())
- {
- if (!o.empty())
- {
- o += " - ";
- }
- o += name;
- }
- if (!streamData::validateTitle(o))
- {
- WLOG("[ADMINCGI sid=" + tos(id) + "] Title update rejected - value not allowed: " + o);
- o.clear();
- }
- o = "StreamTitle='" + o + "';";
- aolxml::node::nodeList_t nodes = aolxml::node::findNodes(n,"/metadata/extension/title");
- if (!nodes.empty())
- {
- for (aolxml::node::nodeList_t::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
- {
- if (*i)
- {
- // skip the first element as that is the current song and not what we want to get
- int seq = atoi((*i)->findAttributeString("seq").c_str());
- if (seq == 2)
- {
- utf8 next = ((*i)->pcdata());
- if (streamData::validateTitle(next))
- {
- o += "StreamNext='" + next + "';";
- }
- break;
- }
- }
- }
- }
- utf8 url = aolxml::subNodeText(n, "/metadata/" + URL(), (utf8)"");
- if (!url.empty())
- {
- utf8::size_type pos = url.find(utf8("://"));
- if (pos == utf8::npos)
- {
- url = "http://" + url;
- }
- o += "StreamUrl='" + url + "';";
- }
- }
- catch(const exception &ex)
- {
- forget(n);
- throw std::runtime_error(ex.what());
- }
- forget(n);
- return o;
- }
- uniString::utf8 metadata::get_song_title_from_3902(const uniString::utf8 &d)
- {
- utf8 o;
- utf8 result;
- aolxml::node *n = 0;
- try
- {
- n = aolxml::node::parse(d.hideAsString());
- utf8 artist = aolxml::subNodeText(n, "/metadata/" + ARTIST(), (utf8)"");
- utf8 name = aolxml::subNodeText(n, "/metadata/" + NAME(), (utf8)"");
- if (!artist.empty())
- {
- if (!result.empty()) result += " - ";
- result += artist;
- }
- if (!name.empty())
- {
- if (!result.empty()) result += " - ";
- result += name;
- }
- }
- catch(const exception &ex)
- {
- forget(n);
- throw std::runtime_error(ex.what());
- }
- forget(n);
- return result;
- }
- uniString::utf8 metadata::get_XX_from_3902(const uniString::utf8& node, const uniString::utf8 &d,
- const uniString::utf8 &old) throw (std::runtime_error)
- {
- utf8 result;
- aolxml::node *n = 0;
- try
- {
- n = aolxml::node::parse(d.hideAsString());
- result = aolxml::subNodeText(n, utf8("/metadata/" + node).hideAsString(), old);
- }
- catch(const exception &ex)
- {
- forget(n);
- throw std::runtime_error(ex.what());
- }
- forget(n);
- return result;
- }
- std::vector<uniString::utf8> metadata::get_nextsongs_from_3902(const uniString::utf8 &d,
- std::vector<uniString::utf8>& oldSongList,
- const bool first) throw (std::runtime_error)
- {
- aolxml::node *n = 0;
- std::vector<uniString::utf8> nextSongList;
- try
- {
- n = aolxml::node::parse(d.hideAsString());
- aolxml::node::nodeList_t nodes = aolxml::node::findNodes(n,"/metadata/extension/title");
- if(!nodes.empty())
- {
- for (aolxml::node::nodeList_t::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
- {
- if (*i)
- {
- // skip the first element as that is the current song and not what we want to hold
- int seq = atoi((*i)->findAttributeString("seq").c_str());
- if ((seq > 1 && !first) || (first && seq == 2))
- {
- nextSongList.push_back((*i)->pcdata());
- }
- if (first)
- {
- break;
- }
- }
- }
- }
- else
- {
- // if there are no nodes then as this could be from a stream-specific metadata
- // update then we need to preserve the existing list so it's not cleared out.
- forget(n);
- return oldSongList;
- }
- }
- catch(const exception &ex)
- {
- forget(n);
- throw std::runtime_error(ex.what());
- }
- forget(n);
- return nextSongList;
- }
|