bool StPlayList::remove(const StString& thePath, const bool theToRemovePhysically) { StString aPath = thePath; StPlayItem* aRemItem = NULL; StMutexAuto anAutoLock(myMutex); if(myCurrent == NULL) { // empty playlist return false; } else if(aPath != myCurrent->getPath()) { // search play item for(StPlayItem* anItem = myFirst; anItem != NULL; anItem = anItem->getNext()) { if(aPath == anItem->getPath()) { aRemItem = anItem; break; } } } else { // walk to another playlist position aRemItem = myCurrent; const bool aPlayedFlag = aRemItem->getPlayedFlag(); if(myCurrent->hasNext()) { myCurrent = myCurrent->getNext(); } else if(myCurrent->hasPrev()) { myCurrent = myCurrent->getPrev(); } else { myCurrent = NULL; myPlayedCount = 0; } if(myCurrent != NULL) { if(aRemItem->getPlayedFlag() != aPlayedFlag) { // the item has not been played yet - mark it as such aRemItem->setPlayedFlag(aPlayedFlag); } else { // one played item has been removed --myPlayedCount; } } } // remove item itself const bool isDeleted = aRemItem != NULL && (!theToRemovePhysically || StFileNode::removeFile(aPath)); if(isDeleted) { delPlayItem(aRemItem); delete aRemItem; } anAutoLock.unlock(); signals.onPlaylistChange(); return isDeleted; }
bool StPlayList::walkToNext(const bool theToForce) { StMutexAuto anAutoLock(myMutex); if(myCurrent == NULL || (myToLoopSingle && !theToForce)) { return false; } else if(myIsShuffle && myItemsCount >= 3) { StPlayItem* aPrev = myCurrent; if(!myStackNext.empty()) { myCurrent = myStackNext.front(); myStackNext.pop_front(); } else { if((myPlayedCount >= (myItemsCount - 1)) || (myPlayedCount == 0)) { // reset the playback counter #ifdef _WIN32 FILETIME aTime; GetSystemTimeAsFileTime(&aTime); myRandGen.setSeed(aTime.dwLowDateTime); #else timeval aTime; gettimeofday(&aTime, NULL); myRandGen.setSeed(aTime.tv_usec); #endif myPlayedCount = 0; myCurrent->setPlayedFlag(!myCurrent->getPlayedFlag()); ST_DEBUG_LOG("Restart the shuffle"); } // determine next random position const size_t aCurrPos = myCurrent->getPosition(); bool aCurrFlag = myCurrent->getPlayedFlag(); StPlayItem* aNextItem = myCurrent; const size_t aNextPos = stMin(size_t(myRandGen.next() * myItemsCount), myItemsCount - 1); if(aNextPos > aCurrPos) { // forward direction for(size_t aNextDiff = aNextPos - aCurrPos; aNextItem != NULL && aNextDiff != 0; --aNextDiff) { aNextItem = aNextItem->getNext(); } } else { // backward direction for(size_t aNextDiff = aCurrPos - aNextPos; aNextItem != NULL && aNextDiff != 0; --aNextDiff) { aNextItem = aNextItem->getPrev(); } } if(aCurrFlag == aNextItem->getPlayedFlag()) { // find nearest position not yet played - prefer item farther from current one StPlayItem* aNextItem1 = aNextPos > aCurrPos ? aNextItem->getNext() : aNextItem->getPrev(); StPlayItem* aNextItem2 = aNextPos > aCurrPos ? aNextItem->getPrev() : aNextItem->getNext(); for(; aNextItem1 != NULL || aNextItem2 != NULL;) { if(aNextItem1 != NULL) { if(aCurrFlag != aNextItem1->getPlayedFlag()) { aNextItem = aNextItem1; break; } aNextItem1 = aNextPos > aCurrPos ? aNextItem1->getNext() : aNextItem1->getPrev(); } if(aNextItem2 != NULL) { if(aCurrFlag != aNextItem2->getPlayedFlag()) { aNextItem = aNextItem2; break; } aNextItem2 = aNextPos > aCurrPos ? aNextItem2->getPrev() : aNextItem2->getNext(); } } if(aCurrFlag == aNextItem->getPlayedFlag()) { // something wrong! ST_DEBUG_LOG("Disaster - next shuffle position not found!"); aCurrFlag = !aCurrFlag; myPlayedCount = 0; } } ST_DEBUG_LOG(aCurrPos + " -> " + aNextItem->getPosition()); ++myPlayedCount; aNextItem->setPlayedFlag(aCurrFlag); myCurrent = aNextItem; } if(aPrev != myCurrent && aPrev != NULL) { myStackPrev.push_back(aPrev); if(myStackPrev.size() > THE_UNDO_LIMIT) { myStackPrev.pop_front(); } } const size_t anItemId = myCurrent->getPosition(); anAutoLock.unlock(); signals.onPositionChange(anItemId); return true; } else if(myCurrent != myLast) { myCurrent = myCurrent->getNext(); const size_t anItemId = myCurrent->getPosition(); anAutoLock.unlock(); signals.onPositionChange(anItemId); return true; } else if(myIsLoopFlag) { return walkToFirst(); } return false; }