Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}