Newer
Older
/*
* Copyright (C) 2019 Kevin Whitaker <eyecreate@eyecreate.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*ByteArray(jsonTrack)
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "minimediaplayer.h"
#include <QProcess>
#include <QJsonDocument>
#include <QJsonObject>
Kevin Whitaker
committed
#include <QtConcurrent/QtConcurrentRun>
MiniMediaPlayer::MiniMediaPlayer(QObject *parent) : QObject(parent)
{
m_player = new QMediaPlayer(this,QMediaPlayer::StreamPlayback);
connect(m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),this,SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
connect(m_player,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(mediaStateChanged(QMediaPlayer::State)));
connect(m_player,SIGNAL(durationChanged(qint64)),this,SLOT(durationChanged(qint64)));
connect(m_player,SIGNAL(positionChanged(qint64)),this,SLOT(positionChanged(qint64)));
connect(m_player,&QMediaPlayer::volumeChanged,this,&MiniMediaPlayer::mediaVolumeChanged);
bool MiniMediaPlayer::isPlaying()
{
return m_player->state() == QMediaPlayer::State::PlayingState;
}
bool MiniMediaPlayer::nextTrack()
{
if(playlist.size() > 1)
{
playlist.pop_front();
Kevin Whitaker
committed
m_player->pause();
m_player->setPosition(0);
QtConcurrent::run([this]() {
m_player->setMedia(getStreamUrlFromUrl(playlist.first().second));
emit playlistChanged(getTrackNames());
});
Kevin Whitaker
committed
else if(playlist.size() == 1)
{
playlist.pop_front();
m_player->stop();
emit playlistChanged(getTrackNames());
}
return false;
}
qint64 MiniMediaPlayer::getCurrentPosition()
{
return m_player->position();
}
qint64 MiniMediaPlayer::getTrackDuration()
{
return m_player->duration();
}
int MiniMediaPlayer::getVolume()
{
return m_player->volume();
}
void MiniMediaPlayer::setVolume(int volume)
{
m_player->setVolume(volume);
}
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
bool MiniMediaPlayer::playPauseTrack(bool playing)
{
if(m_player->state() == QMediaPlayer::State::PlayingState && !playing)
{
m_player->pause();
return true;
}
else if(m_player->state() == QMediaPlayer::State::PausedState && playing)
{
m_player->play();
return true;
}
return false;
}
QList<QString> MiniMediaPlayer::getTrackNames()
{
QList<QString> playlistTitles;
for(QPair<QString,QUrl> item: playlist)
{
playlistTitles.append(item.first);
}
return playlistTitles;
}
QMap<QString, qint64> MiniMediaPlayer::currentState()
{
QMap<QString,qint64> state;
state.insert("duration",m_player->duration());
state.insert("position",m_player->position());
state.insert("state",isPlaying());
return state;
}
void MiniMediaPlayer::durationChanged(qint64 length)
{
emit trackDurationChanged(length);
}
void MiniMediaPlayer::positionChanged(qint64 position)
{
emit trackPositionChanged(position);
Kevin Whitaker
committed
void MiniMediaPlayer::addURLToPlaylist(QUrl mediaUrl)
Kevin Whitaker
committed
QtConcurrent::run([this,mediaUrl](){
if(isValidMediaUrl(mediaUrl))
Kevin Whitaker
committed
bool shouldStartPlaying = false;
if(playlist.size() == 0) shouldStartPlaying = true;
QList<QPair<QString,QUrl>> tracks = getStreamTitlesAndUrlsFromUrl(mediaUrl);
if(tracks.size() > 0)
{
playlist.append(tracks);
emit playlistChanged(getTrackNames());
}
if(shouldStartPlaying && playlist.size() > 0)
{
m_player->setMedia(getStreamUrlFromUrl(playlist.first().second));
}
Kevin Whitaker
committed
});
QUrl MiniMediaPlayer::getStreamUrlFromUrl(QUrl mediaUrl)
//Run youtube-dl on Url and return Url given back.
QProcess youtubedl;
Kevin Whitaker
committed
youtubedl.start("youtube-dl -f bestaudio[acodec=opus]/bestaudio[acodec=vorbis]/bestaudio[acodec=mp3] -g "+mediaUrl.toString());
if(youtubedl.waitForFinished(-1))
{
QByteArray out = youtubedl.readAllStandardOutput();
QString outStr = QString::fromStdString(out.toStdString());
for(QString track:outStr.split('\n'))
{
qDebug() << "Found URL stream:" << track;
return QUrl(track);
}
}
return QUrl();
bool MiniMediaPlayer::isValidMediaUrl(QUrl mediaUrl)
{
//Only support youtube and bandcamp for now.
if(mediaUrl.host().endsWith("youtube.com") || mediaUrl.host().endsWith("bandcamp.com"))
{
//TODO: check more than host?
return true;
}
//For now, allow all urls since worst case youtube-dl will just fail to add anything to playlist.
return true;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
}
void MiniMediaPlayer::mediaStateChanged(QMediaPlayer::State state)
{
if(state == QMediaPlayer::State::PlayingState)
{
emit playStateChanged(true);
}
else
{
emit playStateChanged(false);
}
}
void MiniMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
{
//Make sure to load next track once track has ended.
if(status == QMediaPlayer::MediaStatus::EndOfMedia)
{
//Load next track
nextTrack();
}
else if(status == QMediaPlayer::MediaStatus::InvalidMedia)
{
qWarning() << "Unable to play track.";
}
else if(status == QMediaPlayer::MediaStatus::LoadedMedia)
{
Kevin Whitaker
committed
//Start playing media if more in playlsit
if(playlist.size() > 0) m_player->play();
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
}
}
QList<QPair<QString,QUrl>> MiniMediaPlayer::getStreamTitlesAndUrlsFromUrl(QUrl mediaUrl)
{
QList<QPair<QString,QUrl>> tracks;
//Run youtube-dl on Url and return json given back.
QProcess youtubedl;
youtubedl.start("youtube-dl -f bestaudio -j "+mediaUrl.toString());
if(youtubedl.waitForFinished(-1))
{
//If there is anything in error output, error must have occured.
if(youtubedl.readAllStandardError().size()== 0)
{
QByteArray out = youtubedl.readAllStandardOutput();
QString outStr = QString::fromStdString(out.toStdString());
for(QString jsonTrack:outStr.split('\n'))
{
//Parse urls and titles from json list
QJsonDocument info = QJsonDocument::fromJson(jsonTrack.toUtf8());
if(!info.isNull() && info.isObject())
{
QPair<QString,QUrl> track;
QJsonObject jsonTrackInfo = info.object();
track.first = jsonTrackInfo["title"].toString();
track.second = QUrl(jsonTrackInfo["webpage_url"].toString());
tracks.append(track);
}
}
}
else
{