|
|
|
#include "player.h"
|
|
|
|
|
|
|
|
#include <noatun/playlist.h>
|
|
|
|
#include "engine.h"
|
|
|
|
#include "app.h"
|
|
|
|
#include "titleproxy.h"
|
|
|
|
|
|
|
|
#include <klibloader.h>
|
|
|
|
#include <knotifyclient.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
|
|
|
|
enum ArtsPOS { posIdle=0, posPlaying, posPaused };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Player::Player(TQObject *parent) : TQObject(parent, "Player"),
|
|
|
|
position(-1), mLoopStyle(None), firstTimeout(true)
|
|
|
|
{
|
|
|
|
mEngine=new Engine;
|
|
|
|
connect(&filePos, TQT_SIGNAL(timeout()), TQT_SLOT(posTimeout()));
|
|
|
|
connect(mEngine, TQT_SIGNAL(aboutToPlay()), this, TQT_SLOT(aboutToPlay()));
|
|
|
|
connect(mEngine,
|
|
|
|
TQT_SIGNAL(receivedStreamMeta(const TQString &, const TQString &,
|
|
|
|
const TQString &, const TQString &,
|
|
|
|
const TQString &, const TQString &)),
|
|
|
|
this, TQT_SLOT(
|
|
|
|
slotUpdateStreamMeta(const TQString &, const TQString &,
|
|
|
|
const TQString &, const TQString &,
|
|
|
|
const TQString &, const TQString &))
|
|
|
|
);
|
|
|
|
connect(mEngine, TQT_SIGNAL(playingFailed()), this, TQT_SLOT(forward()));
|
|
|
|
|
|
|
|
handleButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
Player::~Player()
|
|
|
|
{
|
|
|
|
delete mEngine;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Player::isPlaying()
|
|
|
|
{
|
|
|
|
return mEngine->state()==posPlaying;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Player::isPaused()
|
|
|
|
{
|
|
|
|
return mEngine->state()==posPaused;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Player::isStopped()
|
|
|
|
{
|
|
|
|
return mEngine->state()==posIdle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::toggleListView()
|
|
|
|
{
|
|
|
|
napp->playlist()->toggleList();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::handleButtons()
|
|
|
|
{
|
|
|
|
switch (mEngine->state())
|
|
|
|
{
|
|
|
|
case (posPlaying):
|
|
|
|
emit playing();
|
|
|
|
break;
|
|
|
|
case (posPaused):
|
|
|
|
emit paused();
|
|
|
|
break;
|
|
|
|
case (posIdle):
|
|
|
|
emit stopped();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::back()
|
|
|
|
{
|
|
|
|
if (napp->playlist()->previous())
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::stop()
|
|
|
|
{
|
|
|
|
filePos.stop();
|
|
|
|
position=0;
|
|
|
|
mEngine->stop();
|
|
|
|
emit stopped();
|
|
|
|
mCurrent=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::play()
|
|
|
|
{
|
|
|
|
napp->processEvents();
|
|
|
|
bool work=false;
|
|
|
|
firstTimeout=true;
|
|
|
|
|
|
|
|
if (mEngine->state()==posPlaying) // do nothing if already playing
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mEngine->state()==posPaused)
|
|
|
|
{
|
|
|
|
work=mEngine->play();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
mCurrent = napp->playlist()->current();
|
|
|
|
if (!mCurrent)
|
|
|
|
{
|
|
|
|
work=false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mEngine->blockSignals(true);
|
|
|
|
work=mEngine->open(mCurrent);
|
|
|
|
mEngine->blockSignals(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!work)
|
|
|
|
{
|
|
|
|
forward(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
filePos.start(500);
|
|
|
|
emit changed();
|
|
|
|
mEngine->play();
|
|
|
|
}
|
|
|
|
|
|
|
|
handleButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::play(const PlaylistItem &item)
|
|
|
|
{
|
|
|
|
napp->playlist()->setCurrent(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::playpause()
|
|
|
|
{
|
|
|
|
if (mEngine->state()==posPlaying)
|
|
|
|
{
|
|
|
|
filePos.stop();
|
|
|
|
mEngine->pause();
|
|
|
|
// emit paused(); NOT necessary because emitted in handleButtons() (mETz)
|
|
|
|
handleButtons();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::forward(bool allowLoop)
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
if (napp->playlist()->next())
|
|
|
|
play();
|
|
|
|
else if (allowLoop && napp->loopList())
|
|
|
|
if (napp->playlist()->reset(), napp->playlist()->current())
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::skipTo(int msec) // skip to a certain time in the track
|
|
|
|
{
|
|
|
|
if( (current()) && (msec>=0) )
|
|
|
|
{
|
|
|
|
mEngine->seek(msec);
|
|
|
|
position = mEngine->position(); // make sure position is recent
|
|
|
|
emit timeout(); // update the UI
|
|
|
|
emit skipped(msec);
|
|
|
|
emit skipped();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::playCurrent()
|
|
|
|
{
|
|
|
|
if (!mEngine->initialized()) return;
|
|
|
|
stop();
|
|
|
|
mCurrent=0;
|
|
|
|
if (napp->playlist()->current())
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::newCurrent()
|
|
|
|
{
|
|
|
|
// the second half of the following
|
|
|
|
if (!napp->playlist() || !mEngine->initialized())
|
|
|
|
return; // no playlist, or squelch playing as an optimization
|
|
|
|
if ((mEngine->state()!=posPlaying) && napp->autoPlay())
|
|
|
|
playCurrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::posTimeout()
|
|
|
|
{
|
|
|
|
if (mEngine->state()==posIdle)
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
handleButtons();
|
|
|
|
// If you're supposed to loop the song, don't go next
|
|
|
|
// otherwise, do go next
|
|
|
|
if (loopStyle()==Song || napp->playlist()->next())
|
|
|
|
play();
|
|
|
|
else if (loopStyle()==Playlist)
|
|
|
|
{
|
|
|
|
napp->playlist()->reset();
|
|
|
|
play();
|
|
|
|
}
|
|
|
|
else if (napp->loopList())
|
|
|
|
napp->playlist()->reset();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
position = mEngine->position();
|
|
|
|
|
|
|
|
if (current())
|
|
|
|
{
|
|
|
|
current().setLength(mEngine->length());
|
|
|
|
if (current().length() && firstTimeout)
|
|
|
|
{
|
|
|
|
int minutes = (int) ( current().length() / 60 );
|
|
|
|
int seconds = current().length() - minutes * 60;
|
|
|
|
emit newSongLen ( minutes, seconds );
|
|
|
|
firstTimeout = false;
|
|
|
|
emit newSong();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit timeout();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Player::lengthString(int _position)
|
|
|
|
{
|
|
|
|
if (!current())
|
|
|
|
return TQString("--:--/--:--");
|
|
|
|
|
|
|
|
TQString posString;
|
|
|
|
TQString lenString;
|
|
|
|
int secs, seconds, minutes;
|
|
|
|
|
|
|
|
if (_position < 0)
|
|
|
|
_position = position;
|
|
|
|
|
|
|
|
if (_position<0)
|
|
|
|
{
|
|
|
|
posString="--:--/";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // get the position
|
|
|
|
bool remain = napp->displayRemaining() && current();
|
|
|
|
if (remain && current().length()<0)
|
|
|
|
{
|
|
|
|
remain = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remain)
|
|
|
|
{
|
|
|
|
_position = current().length() - _position;
|
|
|
|
}
|
|
|
|
|
|
|
|
secs = _position / 1000; // convert milliseconds -> seconds
|
|
|
|
seconds = secs % 60;
|
|
|
|
minutes = (secs - seconds) / 60;
|
|
|
|
|
|
|
|
// the string has to look like '00:00/00:00'
|
|
|
|
posString.sprintf("%.2d:%.2d/", minutes, seconds);
|
|
|
|
if (remain) posString.prepend('-');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!current() || current().length()<0)
|
|
|
|
{
|
|
|
|
posString+="--:--";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // get the length
|
|
|
|
secs = current().length() / 1000; // convert milliseconds -> seconds
|
|
|
|
seconds = secs % 60;
|
|
|
|
minutes = (secs - seconds) / 60;
|
|
|
|
|
|
|
|
// the string has to look like '00:00/00:00'
|
|
|
|
lenString.sprintf("%.2d:%.2d", minutes, seconds);
|
|
|
|
posString += lenString;
|
|
|
|
}
|
|
|
|
|
|
|
|
return posString;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Player::getLength()
|
|
|
|
{
|
|
|
|
if (!current())
|
|
|
|
return -1;
|
|
|
|
return current().length(); // return track-length in milliseconds
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::openFile(const KURL &f, bool purge, bool autoplay)
|
|
|
|
{
|
|
|
|
if (purge)
|
|
|
|
napp->playlist()->clear();
|
|
|
|
napp->playlist()->addFile(f, autoplay);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::openFile(const KURL::List &f, bool purge, bool autoplay)
|
|
|
|
{
|
|
|
|
if (purge)
|
|
|
|
napp->playlist()->clear();
|
|
|
|
for (KURL::List::ConstIterator i(f.begin()); i != f.end(); ++i)
|
|
|
|
{
|
|
|
|
napp->playlist()->addFile(*i, autoplay);
|
|
|
|
autoplay=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Player::loop()
|
|
|
|
{
|
|
|
|
mLoopStyle++;
|
|
|
|
if (mLoopStyle>Random)
|
|
|
|
mLoopStyle=None;
|
|
|
|
emit loopTypeChange(mLoopStyle);
|
|
|
|
}
|
|
|
|
void Player::loop(int i)
|
|
|
|
{
|
|
|
|
mLoopStyle=i;
|
|
|
|
emit loopTypeChange(mLoopStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::removeCurrent()
|
|
|
|
{
|
|
|
|
if (napp->playlist()->current())
|
|
|
|
napp->playlist()->current().remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::setVolume(int v)
|
|
|
|
{
|
|
|
|
if (v<0) v=0;
|
|
|
|
if (v>100) v=100;
|
|
|
|
mEngine->setVolume(v);
|
|
|
|
emit timeout();
|
|
|
|
emit volumeChanged(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Player::volume() const
|
|
|
|
{
|
|
|
|
return mEngine->volume();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::aboutToPlay()
|
|
|
|
{
|
|
|
|
emit aboutToOpen( mCurrent );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::slotUpdateStreamMeta(
|
|
|
|
const TQString &streamName, const TQString &streamGenre,
|
|
|
|
const TQString &streamUrl, const TQString &streamBitrate,
|
|
|
|
const TQString &trackTitle, const TQString &trackUrl)
|
|
|
|
{
|
|
|
|
PlaylistItem currentItem = napp->playlist()->current();
|
|
|
|
if(currentItem)
|
|
|
|
{
|
|
|
|
currentItem.setProperty("title", trackTitle);
|
|
|
|
currentItem.setProperty("bitrate", streamBitrate);
|
|
|
|
|
|
|
|
if(!streamName.isEmpty())
|
|
|
|
currentItem.setProperty("author", streamName);
|
|
|
|
if(!streamGenre.isEmpty())
|
|
|
|
currentItem.setProperty("genre", streamGenre);
|
|
|
|
if(!trackUrl.isEmpty())
|
|
|
|
currentItem.setProperty("comment", trackUrl);
|
|
|
|
else if(!streamUrl.isEmpty())
|
|
|
|
currentItem.setProperty("comment", streamUrl);
|
|
|
|
else
|
|
|
|
currentItem.clearProperty("comment");
|
|
|
|
emit changed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "player.moc"
|