2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "PlayListFactory.h"
24 #include "video/VideoInfoTag.h"
25 #include "music/tags/MusicInfoTag.h"
26 #include "filesystem/File.h"
27 #include "utils/log.h"
28 #include "utils/URIUtils.h"
29 #include "utils/Variant.h"
30 #include "interfaces/AnnouncementManager.h"
32 //using namespace std;
33 using namespace MUSIC_INFO;
34 using namespace XFILE;
35 using namespace PLAYLIST;
37 CPlayList::CPlayList(int id)
40 m_strPlayListName = "";
41 m_iPlayableItems = -1;
46 void CPlayList::AnnounceRemove(int pos)
52 data["playlistid"] = m_id;
53 data["position"] = pos;
54 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Playlist, "xbmc", "OnRemove", data);
57 void CPlayList::AnnounceClear()
63 data["playlistid"] = m_id;
64 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Playlist, "xbmc", "OnClear", data);
67 void CPlayList::AnnounceAdd(const CFileItemPtr& item, int pos)
73 data["playlistid"] = m_id;
74 data["position"] = pos;
75 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Playlist, "xbmc", "OnAdd", item, data);
78 void CPlayList::Add(const CFileItemPtr &item, int iPosition, int iOrder)
80 int iOldSize = size();
81 if (iPosition < 0 || iPosition >= iOldSize)
83 if (iOrder < 0 || iOrder >= iOldSize)
84 item->m_iprogramCount = iOldSize;
86 item->m_iprogramCount = iOrder;
88 // videodb files are not supported by the filesystem as yet
89 if (item->IsVideoDb())
90 item->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
92 // increment the playable counter
93 item->ClearProperty("unplayable");
94 if (m_iPlayableItems < 0)
99 // set 'IsPlayable' property - needed for properly handling plugin:// URLs
100 item->SetProperty("IsPlayable", true);
102 //CLog::Log(LOGDEBUG,"%s item:(%02i/%02i)[%s]", __FUNCTION__, iPosition, item->m_iprogramCount, item->GetPath().c_str());
103 if (iPosition == iOldSize)
104 m_vecItems.push_back(item);
107 ivecItems it = m_vecItems.begin() + iPosition;
108 m_vecItems.insert(it, 1, item);
109 // correct any duplicate order values
110 if (iOrder < iOldSize)
111 IncrementOrder(iPosition + 1, iOrder);
113 AnnounceAdd(item, iPosition);
116 void CPlayList::Add(const CFileItemPtr &item)
121 void CPlayList::Add(CPlayList& playlist)
123 for (int i = 0; i < (int)playlist.size(); i++)
124 Add(playlist[i], -1, -1);
127 void CPlayList::Add(CFileItemList& items)
129 for (int i = 0; i < (int)items.Size(); i++)
133 void CPlayList::Insert(CPlayList& playlist, int iPosition /* = -1 */)
135 // out of bounds so just add to the end
137 if (iPosition < 0 || iPosition >= iSize)
142 for (int i = 0; i < (int)playlist.size(); i++)
144 int iPos = iPosition + i;
145 Add(playlist[i], iPos, iPos);
149 void CPlayList::Insert(CFileItemList& items, int iPosition /* = -1 */)
151 // out of bounds so just add to the end
153 if (iPosition < 0 || iPosition >= iSize)
158 for (int i = 0; i < (int)items.Size(); i++)
160 Add(items[i], iPosition + i, iPosition + i);
164 void CPlayList::Insert(const CFileItemPtr &item, int iPosition /* = -1 */)
166 // out of bounds so just add to the end
168 if (iPosition < 0 || iPosition >= iSize)
173 Add(item, iPosition, iPosition);
176 void CPlayList::DecrementOrder(int iOrder)
178 if (iOrder < 0) return;
180 // it was the last item so do nothing
181 if (iOrder == size()) return;
183 // fix all items with an order greater than the removed iOrder
185 it = m_vecItems.begin();
186 while (it != m_vecItems.end())
188 CFileItemPtr item = *it;
189 if (item->m_iprogramCount > iOrder)
191 //CLog::Log(LOGDEBUG,"%s fixing item at order %i", __FUNCTION__, item->m_iprogramCount);
192 item->m_iprogramCount--;
198 void CPlayList::IncrementOrder(int iPosition, int iOrder)
200 if (iOrder < 0) return;
202 // fix all items with an order equal or greater to the added iOrder at iPos
204 it = m_vecItems.begin() + iPosition;
205 while (it != m_vecItems.end())
207 CFileItemPtr item = *it;
208 if (item->m_iprogramCount >= iOrder)
210 //CLog::Log(LOGDEBUG,"%s fixing item at order %i", __FUNCTION__, item->m_iprogramCount);
211 item->m_iprogramCount++;
217 void CPlayList::Clear()
219 m_vecItems.erase(m_vecItems.begin(), m_vecItems.end());
220 m_strPlayListName = "";
221 m_iPlayableItems = -1;
222 m_bWasPlayed = false;
227 int CPlayList::size() const
229 return (int)m_vecItems.size();
232 const CFileItemPtr CPlayList::operator[] (int iItem) const
234 if (iItem < 0 || iItem >= size())
237 CLog::Log(LOGERROR, "Error trying to retrieve an item that's out of range");
238 return CFileItemPtr();
240 return m_vecItems[iItem];
243 CFileItemPtr CPlayList::operator[] (int iItem)
245 if (iItem < 0 || iItem >= size())
248 CLog::Log(LOGERROR, "Error trying to retrieve an item that's out of range");
249 return CFileItemPtr();
251 return m_vecItems[iItem];
254 void CPlayList::Shuffle(int iPosition)
257 // nothing to shuffle, just set the flag for later
261 if (iPosition >= size())
265 CLog::Log(LOGDEBUG,"%s shuffling at pos:%i", __FUNCTION__, iPosition);
267 ivecItems it = m_vecItems.begin() + iPosition;
268 random_shuffle(it, m_vecItems.end());
270 // the list is now shuffled!
275 struct SSortPlayListItem
277 static bool PlaylistSort(const CFileItemPtr &left, const CFileItemPtr &right)
279 return (left->m_iprogramCount <= right->m_iprogramCount);
283 void CPlayList::UnShuffle()
285 sort(m_vecItems.begin(), m_vecItems.end(), SSortPlayListItem::PlaylistSort);
286 // the list is now unshuffled!
290 const CStdString& CPlayList::GetName() const
292 return m_strPlayListName;
295 void CPlayList::Remove(const CStdString& strFileName)
300 it = m_vecItems.begin();
301 while (it != m_vecItems.end() )
303 CFileItemPtr item = *it;
304 if (item->GetPath() == strFileName)
306 iOrder = item->m_iprogramCount;
307 it = m_vecItems.erase(it);
308 AnnounceRemove(position);
309 //CLog::Log(LOGDEBUG,"PLAYLIST, removing item at order %i", iPos);
317 DecrementOrder(iOrder);
320 int CPlayList::FindOrder(int iOrder) const
322 for (int i = 0; i < size(); i++)
324 if (m_vecItems[i]->m_iprogramCount == iOrder)
330 // remove item from playlist by position
331 void CPlayList::Remove(int position)
334 if (position >= 0 && position < (int)m_vecItems.size())
336 iOrder = m_vecItems[position]->m_iprogramCount;
337 m_vecItems.erase(m_vecItems.begin() + position);
339 DecrementOrder(iOrder);
341 AnnounceRemove(position);
344 int CPlayList::RemoveDVDItems()
346 std::vector <CStdString> vecFilenames;
348 // Collect playlist items from DVD share
350 it = m_vecItems.begin();
351 while (it != m_vecItems.end() )
353 CFileItemPtr item = *it;
354 if ( item->IsCDDA() || item->IsOnDVD() )
356 vecFilenames.push_back( item->GetPath() );
361 // Delete them from playlist
362 int nFileCount = vecFilenames.size();
365 std::vector <CStdString>::iterator it;
366 it = vecFilenames.begin();
367 while (it != vecFilenames.end() )
369 CStdString& strFilename = *it;
370 Remove( strFilename );
373 vecFilenames.erase( vecFilenames.begin(), vecFilenames.end() );
378 bool CPlayList::Swap(int position1, int position2)
383 (position1 >= size()) ||
384 (position2 >= size())
392 // swap the ordinals before swapping the items!
393 //CLog::Log(LOGDEBUG,"PLAYLIST swapping items at orders (%i, %i)",m_vecItems[position1]->m_iprogramCount,m_vecItems[position2]->m_iprogramCount);
394 std::swap(m_vecItems[position1]->m_iprogramCount, m_vecItems[position2]->m_iprogramCount);
398 std::swap(m_vecItems[position1], m_vecItems[position2]);
402 void CPlayList::SetUnPlayable(int iItem)
404 if (iItem < 0 || iItem >= size())
406 CLog::Log(LOGWARNING, "Attempt to set unplayable index %d", iItem);
410 CFileItemPtr item = m_vecItems[iItem];
411 if (!item->GetProperty("unplayable").asBoolean())
413 item->SetProperty("unplayable", true);
419 bool CPlayList::Load(const CStdString& strFileName)
422 m_strBasePath = URIUtils::GetDirectory(strFileName);
425 if (!file.Open(strFileName))
428 if (file.GetLength() > 1024*1024)
430 CLog::Log(LOGWARNING, "%s - File is larger than 1 MB, most likely not a playlist", __FUNCTION__);
434 return LoadData(file);
437 bool CPlayList::LoadData(std::istream &stream)
439 // try to read as a string
440 std::ostringstream ostr;
441 ostr << stream.rdbuf();
442 return LoadData(ostr.str());
445 bool CPlayList::LoadData(const CStdString& strData)
451 bool CPlayList::Expand(int position)
453 CFileItemPtr item = m_vecItems[position];
454 std::auto_ptr<CPlayList> playlist (CPlayListFactory::Create(*item.get()));
455 if ( NULL == playlist.get())
458 if(!playlist->Load(item->GetPath()))
461 // remove any item that points back to itself
462 for(int i = 0;i<playlist->size();i++)
464 if( (*playlist)[i]->GetPath().Equals( item->GetPath() ) )
471 if(playlist->size() <= 0)
475 Insert(*playlist, position);
479 void CPlayList::UpdateItem(const CFileItem *item)
483 for (ivecItems it = m_vecItems.begin(); it != m_vecItems.end(); ++it)
485 CFileItemPtr playlistItem = *it;
486 if (playlistItem->IsSamePath(item))
488 CStdString temp = playlistItem->GetPath(); // save path, it may have been altered
489 *playlistItem = *item;
490 playlistItem->SetPath(temp);
496 const CStdString& CPlayList::ResolveURL(const CFileItemPtr &item ) const
498 if (item->IsMusicDb() && item->HasMusicInfoTag())
499 return item->GetMusicInfoTag()->GetURL();
501 return item->GetPath();