SHARE
TWEET

Marcos

Marcos12teles Feb 26th, 2020 101 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Skip to content
  2.  xbmc / xbmc
  3. Sign up
  4. Code Issues 462 Pull requests 211 Projects 6 Actions Security Pulse
  5. Join GitHub today
  6. GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
  7.  
  8. xbmc/xbmc/playlists/PlayListM3U.cpp
  9. @Rechi Rechi [modernize] use-emplace
  10. 8b9ef63 on 16 Sep 2019
  11. 275 lines (236 sloc)  8.87 KB
  12.  
  13. /*
  14.  *  Copyright (C) 2005-2018 Team Kodi
  15.  *  This file is part of Kodi - https://kodi.tv
  16.  *
  17.  *  SPDX-License-Identifier: GPL-2.0-or-later
  18.  *  See LICENSES/README.md for more information.
  19.  */
  20.  
  21. #include "PlayListM3U.h"
  22.  
  23. #include "URL.h"
  24. #include "Util.h"
  25. #include "filesystem/File.h"
  26. #include "music/tags/MusicInfoTag.h"
  27. #include "utils/CharsetConverter.h"
  28. #include "utils/URIUtils.h"
  29. #include "utils/log.h"
  30. #include "video/VideoInfoTag.h"
  31.  
  32. #include <inttypes.h>
  33.  
  34. using namespace PLAYLIST;
  35. using namespace XFILE;
  36.  
  37. const char* CPlayListM3U::StartMarker = "#EXTCPlayListM3U::M3U";
  38. const char* CPlayListM3U::InfoMarker = "#EXTINF";
  39. const char* CPlayListM3U::ArtistMarker = "#EXTART";
  40. const char* CPlayListM3U::AlbumMarker = "#EXTALB";
  41. const char* CPlayListM3U::PropertyMarker = "#KODIPROP";
  42. const char* CPlayListM3U::VLCOptMarker = "#EXTVLCOPT";
  43. const char* CPlayListM3U::StreamMarker = "#EXT-X-STREAM-INF";
  44. const char* CPlayListM3U::BandwidthMarker = "BANDWIDTH";
  45. const char* CPlayListM3U::OffsetMarker = "#EXT-KX-OFFSET";
  46.  
  47. // example m3u file:
  48. //   #EXTM3U
  49. //   #EXTART:Demo Artist
  50. //   #EXTALB:Demo Album
  51. //   #KODIPROP:name=value
  52. //   #EXTINF:5,demo
  53. //   E:\Program Files\Winamp3\demo.mp3
  54.  
  55.  
  56.  
  57. // example m3u8 containing streams of different bitrates
  58. //   #EXTM3U
  59. //   #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1600000
  60. //   playlist_1600.m3u8
  61. //   #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=3000000
  62. //   playlist_3000.m3u8
  63. //   #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=800000
  64. //   playlist_800.m3u8
  65.  
  66.  
  67. CPlayListM3U::CPlayListM3U(void) = default;
  68.  
  69. CPlayListM3U::~CPlayListM3U(void) = default;
  70.  
  71.  
  72. bool CPlayListM3U::Load(const std::string& strFileName)
  73. {
  74.   char szLine[4096];
  75.   std::string strLine;
  76.   std::string strInfo;
  77.   std::vector<std::pair<std::string, std::string> > properties;
  78.  
  79.   int lDuration = 0;
  80.   int iStartOffset = 0;
  81.   int iEndOffset = 0;
  82.  
  83.   Clear();
  84.  
  85.   m_strPlayListName = URIUtils::GetFileName(strFileName);
  86.   URIUtils::GetParentPath(strFileName, m_strBasePath);
  87.  
  88.   CFile file;
  89.   if (!file.Open(strFileName) )
  90.   {
  91.     file.Close();
  92.     return false;
  93.   }
  94.  
  95.   while (file.ReadString(szLine, 4095))
  96.   {
  97.     strLine = szLine;
  98.     StringUtils::Trim(strLine);
  99.  
  100.     if (StringUtils::StartsWith(strLine, InfoMarker))
  101.     {
  102.       // start of info
  103.       size_t iColon = strLine.find(":");
  104.       size_t iComma = strLine.find(",");
  105.       if (iColon != std::string::npos &&
  106.           iComma != std::string::npos &&
  107.           iComma > iColon)
  108.       {
  109.         // Read the info and duration
  110.         iColon++;
  111.         std::string strLength = strLine.substr(iColon, iComma - iColon);
  112.         lDuration = atoi(strLength.c_str());
  113.         iComma++;
  114.         strInfo = strLine.substr(iComma);
  115.         g_charsetConverter.unknownToUTF8(strInfo);
  116.       }
  117.     }
  118.     else if (StringUtils::StartsWith(strLine, OffsetMarker))
  119.     {
  120.       size_t iColon = strLine.find(":");
  121.       size_t iComma = strLine.find(",");
  122.       if (iColon != std::string::npos &&
  123.         iComma != std::string::npos &&
  124.         iComma > iColon)
  125.       {
  126.         // Read the start and end offset
  127.         iColon++;
  128.         iStartOffset = atoi(strLine.substr(iColon, iComma - iColon).c_str());
  129.         iComma++;
  130.         iEndOffset = atoi(strLine.substr(iComma).c_str());
  131.       }
  132.     }
  133.     else if (StringUtils::StartsWith(strLine, PropertyMarker)
  134.     || StringUtils::StartsWith(strLine, VLCOptMarker))
  135.     {
  136.       size_t iColon = strLine.find(":");
  137.       size_t iEqualSign = strLine.find("=");
  138.       if (iColon != std::string::npos &&
  139.         iEqualSign != std::string::npos &&
  140.         iEqualSign > iColon)
  141.       {
  142.         std::string strFirst, strSecond;
  143.         properties.emplace_back(
  144.           StringUtils::Trim((strFirst = strLine.substr(iColon + 1, iEqualSign - iColon - 1))),
  145.           StringUtils::Trim((strSecond = strLine.substr(iEqualSign + 1))));
  146.       }
  147.     }
  148.     else if (strLine != StartMarker &&
  149.              !StringUtils::StartsWith(strLine, ArtistMarker) &&
  150.              !StringUtils::StartsWith(strLine, AlbumMarker))
  151.     {
  152.       std::string strFileName = strLine;
  153.  
  154.       if (!strFileName.empty() && strFileName[0] == '#')
  155.         continue; // assume a comment or something else we don't support
  156.  
  157.       // Skip self - do not load playlist recursively
  158.       // We compare case-less in case user has input incorrect case of the current playlist
  159.       if (StringUtils::EqualsNoCase(URIUtils::GetFileName(strFileName), m_strPlayListName))
  160.         continue;
  161.  
  162.       if (strFileName.length() > 0)
  163.       {
  164.         g_charsetConverter.unknownToUTF8(strFileName);
  165.  
  166.         // If no info was read from from the extended tag information, use the file name
  167.         if (strInfo.length() == 0)
  168.         {
  169.           strInfo = URIUtils::GetFileName(strFileName);
  170.         }
  171.  
  172.         // should substitution occur before or after charset conversion??
  173.         strFileName = URIUtils::SubstitutePath(strFileName);
  174.  
  175.         // Get the full path file name and add it to the the play list
  176.         CUtil::GetQualifiedFilename(m_strBasePath, strFileName);
  177.         CFileItemPtr newItem(new CFileItem(strInfo));
  178.         newItem->SetPath(strFileName);
  179.         if (iStartOffset != 0 || iEndOffset != 0)
  180.         {
  181.           newItem->m_lStartOffset = iStartOffset;
  182.           newItem->m_lStartPartNumber = 1;
  183.           newItem->SetProperty("item_start", iStartOffset);
  184.           newItem->m_lEndOffset = iEndOffset;
  185.           // Prevent load message from file and override offset set here
  186.           newItem->GetMusicInfoTag()->SetLoaded();
  187.           newItem->GetMusicInfoTag()->SetTitle(strInfo);
  188.           if (iEndOffset)
  189.             lDuration = static_cast<int>(CUtil::ConvertMilliSecsToSecsIntRounded(iEndOffset - iStartOffset));
  190.         }
  191.         if (newItem->IsVideo() && !newItem->HasVideoInfoTag()) // File is a video and needs a VideoInfoTag
  192.           newItem->GetVideoInfoTag()->Reset(); // Force VideoInfoTag creation
  193.         if (lDuration && newItem->IsAudio())
  194.           newItem->GetMusicInfoTag()->SetDuration(lDuration);
  195.         for (auto &prop : properties)
  196.         {
  197.           newItem->SetProperty(prop.first, prop.second);
  198.         }
  199.  
  200.         newItem->SetMimeType(newItem->GetProperty("mimetype").asString());
  201.         if (!newItem->GetMimeType().empty())
  202.           newItem->SetContentLookup(false);
  203.  
  204.         Add(newItem);
  205.  
  206.         // Reset the values just in case there part of the file have the extended marker
  207.         // and part don't
  208.         strInfo = "";
  209.         lDuration = 0;
  210.         iStartOffset = 0;
  211.         iEndOffset = 0;
  212.         properties.clear();
  213.       }
  214.     }
  215.   }
  216.  
  217.   file.Close();
  218.   return true;
  219. }
  220.  
  221. void CPlayListM3U::Save(const std::string& strFileName) const
  222. {
  223.   if (!m_vecItems.size())
  224.     return;
  225.   std::string strPlaylist = CUtil::MakeLegalPath(strFileName);
  226.   CFile file;
  227.   if (!file.OpenForWrite(strPlaylist,true))
  228.   {
  229.     CLog::Log(LOGERROR, "Could not save M3U playlist: [%s]", strPlaylist.c_str());
  230.     return;
  231.   }
  232.   std::string strLine = StringUtils::Format("%s\n",StartMarker);
  233.   if (file.Write(strLine.c_str(), strLine.size()) != static_cast<ssize_t>(strLine.size()))
  234.     return; // error
  235.  
  236.   for (int i = 0; i < (int)m_vecItems.size(); ++i)
  237.   {
  238.     CFileItemPtr item = m_vecItems[i];
  239.     std::string strDescription=item->GetLabel();
  240.     g_charsetConverter.utf8ToStringCharset(strDescription);
  241.     strLine = StringUtils::Format( "%s:%i,%s\n", InfoMarker, item->GetMusicInfoTag()->GetDuration() / 1000, strDescription.c_str() );
  242.     if (file.Write(strLine.c_str(), strLine.size()) != static_cast<ssize_t>(strLine.size()))
  243.       return; // error
  244.     if (item->m_lStartOffset != 0 || item->m_lEndOffset != 0)
  245.     {
  246.       strLine = StringUtils::Format("%s:%" PRIi64 ",%" PRIi64 "\n", OffsetMarker, item->m_lStartOffset, item->m_lEndOffset);
  247.       file.Write(strLine.c_str(),strLine.size());
  248.     }
  249.     std::string strFileName = ResolveURL(item);
  250.     g_charsetConverter.utf8ToStringCharset(strFileName);
  251.     strLine = StringUtils::Format("%s\n",strFileName.c_str());
  252.     if (file.Write(strLine.c_str(), strLine.size()) != static_cast<ssize_t>(strLine.size()))
  253.       return; // error
  254.   }
  255.   file.Close();
  256. }
  257.  
  258. std::map< std::string, std::string > CPlayListM3U::ParseStreamLine(const std::string &streamLine)
  259. {
  260.   std::map< std::string, std::string > params;
  261.  
  262.   // ensure the line has something beyond the stream marker and ':'
  263.   if (streamLine.size() < strlen(StreamMarker) + 2)
  264.     return params;
  265.  
  266.   // get the actual params following the :
  267.   std::string strParams(streamLine.substr(strlen(StreamMarker) + 1));
  268.  
  269.   // separate the parameters
  270.   std::vector<std::string> vecParams = StringUtils::Split(strParams, ",");
  271.   for (std::vector<std::string>::iterator i = vecParams.begin(); i != vecParams.end(); ++i)
  272.   {
  273.     // split the param, ensure there was an =
  274.     StringUtils::Trim(*i);
  275.     std::vector<std::string> vecTuple = StringUtils::Split(*i, "=");
  276.     if (vecTuple.size() < 2)
  277.       continue;
  278.  
  279.     // remove white space from name and value and store it in the dictionary
  280.     StringUtils::Trim(vecTuple[0]);
  281.     StringUtils::Trim(vecTuple[1]);
  282.     params[vecTuple[0]] = vecTuple[1];
  283.   }
  284.  
  285.   return params;
  286. }
  287.  
  288. © 2020 GitHub, Inc.
  289. Terms
  290. Privacy
  291. Security
  292. Status
  293. Help
  294. Contact GitHub
  295. Pricing
  296. API
  297. Training
  298. Blog
  299. About
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top