2017-10-29 14:47:36 +03:00
|
|
|
#include "sync.h"
|
2017-11-09 23:09:59 +03:00
|
|
|
#include <QtSql>
|
|
|
|
#include <QMultimedia>
|
|
|
|
#include <QSqlQuery>
|
2017-11-11 14:03:14 +03:00
|
|
|
#include "exaptions.h"
|
2017-12-17 02:05:07 +03:00
|
|
|
#include "chronotime.h"
|
2017-11-06 01:33:16 +03:00
|
|
|
|
2017-11-09 23:09:59 +03:00
|
|
|
#ifdef QT_DEBUG
|
|
|
|
#include <QDebug>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace syncLib{
|
|
|
|
|
2017-11-28 20:32:54 +03:00
|
|
|
Sync::Sync(const QString address, int port, const QString &datadir):
|
2017-11-27 02:01:47 +03:00
|
|
|
node(nullptr),
|
|
|
|
player(nullptr),
|
2017-12-03 23:08:43 +03:00
|
|
|
curentSong(nullptr)
|
2017-11-27 02:01:47 +03:00
|
|
|
{
|
2017-11-28 20:32:54 +03:00
|
|
|
node = new Node(address , this->port = port);
|
2017-11-27 22:59:59 +03:00
|
|
|
|
2017-12-13 22:40:29 +03:00
|
|
|
player = new Player(BUFFER_NAME,nullptr,QMediaPlayer::LowLatency);
|
2017-11-11 14:03:14 +03:00
|
|
|
if(!player->isAvailable()){
|
|
|
|
throw MediaException();
|
|
|
|
}
|
2017-11-27 02:01:47 +03:00
|
|
|
|
2017-11-27 22:59:59 +03:00
|
|
|
fbroadcaster = false;
|
2018-01-14 15:29:42 +03:00
|
|
|
resyncCount = 0;
|
2017-11-27 22:59:59 +03:00
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
sql = new MySql(datadir);
|
|
|
|
sql->updateAvailableSongs(playList);
|
2017-11-27 02:01:47 +03:00
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
connect(node, SIGNAL(Message(ETcpSocket*)), SLOT(packageRender(ETcpSocket*)));
|
|
|
|
connect(&deepScaner, SIGNAL(scaned(QList<ETcpSocket*>*)), SLOT(deepScaned(QList<ETcpSocket*>*)));
|
|
|
|
connect(player, SIGNAL(positionChanged(qint64)), SIGNAL(seekChanged(qint64)));
|
|
|
|
connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(endPlay(QMediaPlayer::State)));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sync::findHeader(const Song &song){
|
|
|
|
|
|
|
|
for(SongHeader & header: playList){
|
|
|
|
if(header == static_cast<SongHeader>(song)){
|
|
|
|
curentSong = &header;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2017-11-09 23:09:59 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::play(const SongHeader &header, bool fbroadcast){
|
2017-12-02 14:35:39 +03:00
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
Song song;
|
|
|
|
SongHeader newheader = header;
|
|
|
|
newheader.id = -1;
|
2018-01-09 22:14:54 +03:00
|
|
|
if(!sql->load(newheader, song)){
|
2017-11-20 00:37:12 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-05 21:25:55 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
return Sync::play(song, fbroadcast);
|
2017-11-20 00:37:12 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::play(const Song &song, bool fbroadcast){
|
2017-12-02 14:35:39 +03:00
|
|
|
|
|
|
|
if(!song.isValid()){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
if(!player->setMediaFromBytes(song.getSource())){
|
2017-12-13 22:40:29 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-27 02:01:47 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
fbroadcaster = fbroadcast;
|
2018-01-14 15:29:42 +03:00
|
|
|
|
|
|
|
if(!findHeader(song) && sql->save(song) > -1 &&
|
|
|
|
sql->updateAvailableSongs(playList) && !findHeader(song)){
|
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(fbroadcaster){
|
2018-01-09 22:14:54 +03:00
|
|
|
player->play();
|
|
|
|
sync();
|
|
|
|
}else{
|
2018-01-14 15:29:42 +03:00
|
|
|
player->syncBegin();
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
2017-11-11 20:35:30 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::play(int id_song, bool fbroadcast){
|
2017-11-11 20:35:30 +03:00
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
SongHeader header;
|
|
|
|
header.id = id_song;
|
2017-11-11 20:35:30 +03:00
|
|
|
Song song;
|
2017-12-24 22:04:40 +03:00
|
|
|
sql->load(header, song);
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
return Sync::play(song, fbroadcast);
|
2017-11-11 20:35:30 +03:00
|
|
|
}
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
bool Sync::play(QString url){
|
2017-12-06 12:10:04 +03:00
|
|
|
int id = addNewSong(url);
|
|
|
|
if(id < 0){
|
2017-11-11 20:35:30 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-03 23:08:43 +03:00
|
|
|
|
2017-12-06 12:10:04 +03:00
|
|
|
return Sync::play(id);
|
2017-11-11 20:35:30 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::pause(bool state){
|
|
|
|
|
|
|
|
if(!fbroadcaster)
|
|
|
|
return false;
|
|
|
|
|
2017-12-03 17:22:59 +03:00
|
|
|
if(state){
|
|
|
|
player->pause();
|
|
|
|
}else{
|
|
|
|
player->play();
|
2018-01-09 22:14:54 +03:00
|
|
|
sync();
|
|
|
|
|
2017-12-03 17:22:59 +03:00
|
|
|
}
|
2018-01-09 22:14:54 +03:00
|
|
|
|
|
|
|
return true;
|
2017-11-11 20:35:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sync::stop(){
|
|
|
|
player->stop();
|
|
|
|
}
|
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
void Sync::jump(const qint64 seek){
|
2017-11-11 20:35:30 +03:00
|
|
|
player->setPosition(seek);
|
2017-11-11 14:03:14 +03:00
|
|
|
}
|
|
|
|
|
2018-01-14 15:29:42 +03:00
|
|
|
bool Sync::isReadyToSync()const{
|
|
|
|
return !fbroadcaster && player->isSeekable()
|
|
|
|
&& (player->state() == QMediaPlayer::PlayingState);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::sync(const Syncer &sync, milliseconds ping){
|
2018-01-14 15:29:42 +03:00
|
|
|
if(!isReadyToSync()){
|
2018-01-09 17:59:15 +03:00
|
|
|
return false;
|
|
|
|
}
|
2018-01-09 22:14:54 +03:00
|
|
|
player->setPosition(sync.seek + ping);
|
2018-01-14 15:29:42 +03:00
|
|
|
player->syncEnd();
|
|
|
|
|
|
|
|
return true;
|
2017-12-17 14:27:21 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
}
|
2017-12-17 14:27:21 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
void Sync::sync(){
|
2017-12-17 14:27:21 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
if(fbroadcaster)
|
|
|
|
QTimer::singleShot(SYNC_TIME, [=]() {
|
2018-01-09 17:59:15 +03:00
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
package pac;
|
|
|
|
if(!createPackage(t_sync, pac)){
|
|
|
|
throw CreatePackageExaption();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
node->WriteAll(pac.parseTo());
|
|
|
|
});
|
2017-11-20 00:37:12 +03:00
|
|
|
}
|
|
|
|
|
2017-11-27 19:43:11 +03:00
|
|
|
bool Sync::addNode(const QString ip, int port){
|
|
|
|
if(!node->addNode(ip, port))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rescan();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sync::scan(){
|
|
|
|
|
|
|
|
rescan(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<ETcpSocket*>& Sync::getServersList() const{
|
|
|
|
return servers;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sync::listen(ETcpSocket *server){
|
|
|
|
if(!server){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!server->getSource()->isOpen() && server->getSource()->open(QIODevice::ReadWrite)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
package pac;
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
if(!createPackage(t_play, pac)){
|
2017-11-27 19:43:11 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return server->Write(pac.parseTo());
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
bool Sync::createPackage(Type type, package &pac){
|
|
|
|
|
2017-11-20 00:37:12 +03:00
|
|
|
pac.clear();
|
|
|
|
|
2017-11-21 16:44:55 +03:00
|
|
|
pac.type = type;
|
2017-11-20 00:37:12 +03:00
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(type & TypePackage::t_sync && fbroadcaster){
|
2018-01-09 22:14:54 +03:00
|
|
|
pac.playdata.seek = player->position();
|
2017-11-20 00:37:12 +03:00
|
|
|
|
2017-11-21 16:44:55 +03:00
|
|
|
}
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(type & TypePackage::t_song_h && fbroadcaster){
|
2017-12-03 23:08:43 +03:00
|
|
|
if(!curentSong)
|
2017-11-20 00:37:12 +03:00
|
|
|
return false;
|
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
pac.header = *curentSong;
|
2017-11-20 00:37:12 +03:00
|
|
|
|
2017-11-21 16:44:55 +03:00
|
|
|
}
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(type & TypePackage::t_song && fbroadcaster){
|
2017-12-03 23:08:43 +03:00
|
|
|
if(!curentSong)
|
2017-11-20 00:37:12 +03:00
|
|
|
return false;
|
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
if(!sql->load(*curentSong, pac.source))
|
2017-11-20 00:37:12 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
2017-11-24 21:17:41 +03:00
|
|
|
|
2017-11-22 20:05:53 +03:00
|
|
|
if(fbroadcaster)
|
|
|
|
pac.type = TypePackage(pac.type | t_brodcaster);
|
2017-11-21 16:44:55 +03:00
|
|
|
|
2017-11-20 00:37:12 +03:00
|
|
|
return pac.isValid();
|
|
|
|
}
|
|
|
|
|
2017-11-22 20:05:53 +03:00
|
|
|
void Sync::packageRender(ETcpSocket *socket){
|
|
|
|
|
|
|
|
QByteArray *array;
|
|
|
|
while((array = socket->topStack())){
|
2017-11-24 21:17:41 +03:00
|
|
|
package pkg;
|
|
|
|
if(!pkg.parseFrom((*array))){
|
|
|
|
throw BadAnswerExaption();
|
2017-12-16 16:15:25 +03:00
|
|
|
socket->nextItem();
|
2017-11-24 21:17:41 +03:00
|
|
|
continue;
|
|
|
|
}
|
2017-11-22 20:05:53 +03:00
|
|
|
// package answer;
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
// scaning servers
|
2017-11-22 20:05:53 +03:00
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(pkg.getType() & t_brodcaster && servers.indexOf(socket) == -1){
|
|
|
|
servers.append(socket);
|
2017-12-03 17:22:59 +03:00
|
|
|
emit networkStateChange();
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!(pkg.getType() & t_brodcaster) && servers.indexOf(socket) != -1){
|
|
|
|
servers.removeOne(socket);
|
2017-12-03 17:22:59 +03:00
|
|
|
emit networkStateChange();
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
2017-11-22 20:05:53 +03:00
|
|
|
|
2018-01-14 15:29:42 +03:00
|
|
|
// if(fbroadcaster == (pkg.getType() & t_brodcaster)){
|
|
|
|
// throw BrodcastConflict();
|
|
|
|
// socket->nextItem();
|
|
|
|
// continue;
|
|
|
|
// }
|
2017-11-24 21:17:41 +03:00
|
|
|
|
|
|
|
if(pkg.getType() & t_brodcaster){
|
|
|
|
|
|
|
|
// if requst from server
|
2018-01-14 13:17:38 +03:00
|
|
|
if(pkg.getType() & t_sync && !sync(pkg.getPlayData(), 10)){
|
2018-01-09 22:14:54 +03:00
|
|
|
|
2018-01-14 15:29:42 +03:00
|
|
|
QTimer::singleShot(RESYNC_TIME, [=]() {
|
|
|
|
package pac;
|
|
|
|
|
|
|
|
if(resyncCount < MAX_RESYNC_COUNT){
|
|
|
|
|
|
|
|
if(!createPackage(t_sync, pac)){
|
|
|
|
throw CreatePackageExaption();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
resyncCount++;
|
|
|
|
|
|
|
|
}else{
|
|
|
|
resyncCount = 0;
|
|
|
|
throw SyncCountError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
node->WriteAll(pac.parseTo());
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (pkg.getType() & t_sync){
|
|
|
|
resyncCount = 0;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
if(pkg.getType() & t_play && !play(pkg.getHeader(), false) && !play(pkg.getSong(), false)){
|
2017-12-02 14:35:39 +03:00
|
|
|
|
|
|
|
Type requestType = t_song_h;
|
2017-11-24 21:17:41 +03:00
|
|
|
|
2017-12-02 14:35:39 +03:00
|
|
|
if(pkg.getType() & t_song_h)
|
|
|
|
requestType = t_song;
|
|
|
|
|
|
|
|
package answer;
|
2018-01-09 22:14:54 +03:00
|
|
|
if(!createPackage(requestType | t_play, answer)){
|
2017-12-02 14:35:39 +03:00
|
|
|
throw CreatePackageExaption();
|
2017-12-16 16:15:25 +03:00
|
|
|
socket->nextItem();
|
|
|
|
continue;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
2018-01-10 11:20:19 +03:00
|
|
|
socket->Write(answer.parseTo());
|
|
|
|
}
|
2018-01-14 15:29:42 +03:00
|
|
|
else if(pkg.getType() & t_play){
|
2018-01-11 23:01:47 +03:00
|
|
|
|
2018-01-10 11:20:19 +03:00
|
|
|
package answer;
|
|
|
|
if(!createPackage(t_sync, answer)){
|
|
|
|
throw CreatePackageExaption();
|
|
|
|
socket->nextItem();
|
|
|
|
continue;
|
|
|
|
}
|
2017-12-02 14:35:39 +03:00
|
|
|
socket->Write(answer.parseTo());
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
|
|
|
|
|
2017-11-24 21:17:41 +03:00
|
|
|
if(pkg.getType() & t_close){
|
|
|
|
socket->getSource()->close();
|
|
|
|
node->getClients()->removeOne(socket);
|
|
|
|
delete socket;
|
2017-12-16 16:15:25 +03:00
|
|
|
return;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if(pkg.getType() & t_what){
|
|
|
|
package answer;
|
|
|
|
if(!createPackage(t_void, answer)){
|
|
|
|
throw CreatePackageExaption();
|
2017-12-16 16:15:25 +03:00
|
|
|
socket->nextItem();
|
|
|
|
continue;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
socket->Write(answer.parseTo());
|
|
|
|
}
|
|
|
|
|
2017-12-02 14:35:39 +03:00
|
|
|
}else{
|
|
|
|
|
2018-01-09 22:14:54 +03:00
|
|
|
// if requst from client
|
|
|
|
if(pkg.getType() & t_play & t_sync){
|
2017-12-03 23:08:43 +03:00
|
|
|
if(!curentSong){
|
2017-11-24 21:17:41 +03:00
|
|
|
throw SyncError();
|
2017-12-16 16:15:25 +03:00
|
|
|
socket->nextItem();
|
|
|
|
continue;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
package answer;
|
2018-01-09 22:14:54 +03:00
|
|
|
if(!createPackage(pkg.getType() & ~t_what & ~t_stop & ~t_brodcaster, answer)){
|
2017-11-24 21:17:41 +03:00
|
|
|
throw CreatePackageExaption();
|
2017-12-16 16:15:25 +03:00
|
|
|
socket->nextItem();
|
|
|
|
continue;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
socket->Write(answer.parseTo());
|
|
|
|
|
|
|
|
if(pkg.getType() & t_close){
|
|
|
|
socket->getSource()->close();
|
|
|
|
node->getClients()->removeOne(socket);
|
|
|
|
delete socket;
|
2017-12-16 16:15:25 +03:00
|
|
|
return;
|
2017-11-24 21:17:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-11-22 20:05:53 +03:00
|
|
|
|
2017-11-26 19:19:43 +03:00
|
|
|
socket->nextItem();
|
2017-11-22 20:05:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-22 22:34:55 +03:00
|
|
|
void Sync::rescan(bool deep){
|
2017-11-22 20:05:53 +03:00
|
|
|
package pac;
|
|
|
|
if(!createPackage(t_what,pac)){
|
2017-11-24 21:17:41 +03:00
|
|
|
throw CreatePackageExaption();
|
2017-11-22 20:05:53 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
node->WriteAll(pac.parseTo());
|
2017-11-22 22:34:55 +03:00
|
|
|
|
|
|
|
if(deep){
|
|
|
|
deepScaner.setInterval(DEEP_SCANER_INTERVAL);
|
2017-11-27 19:43:11 +03:00
|
|
|
deepScaner.scane(port);
|
2017-11-22 22:34:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sync::deepScaned(QList<ETcpSocket *> * list){
|
|
|
|
package pac;
|
2018-01-10 19:24:09 +03:00
|
|
|
if(!createPackage(t_what, pac)){
|
2017-11-24 21:17:41 +03:00
|
|
|
throw CreatePackageExaption();
|
2017-11-22 22:34:55 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
QByteArray array = pac.parseTo();
|
|
|
|
for(ETcpSocket * i: *list){
|
2017-12-02 13:22:20 +03:00
|
|
|
node->addNode(i);
|
2017-11-22 22:34:55 +03:00
|
|
|
i->Write(array);
|
|
|
|
}
|
2017-11-22 20:05:53 +03:00
|
|
|
}
|
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
void Sync::endPlay(QMediaPlayer::State state){
|
|
|
|
if(state == QMediaPlayer::StoppedState){
|
|
|
|
curentSong = nullptr;
|
|
|
|
fbroadcaster = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-26 19:19:43 +03:00
|
|
|
QString Sync::getVersion(){
|
|
|
|
return QString(tr("Version") + "%0.%1.%2").arg(MAJOR_VERSION).arg(MINOR_VERSION).arg(REVISION_VERSION);
|
|
|
|
}
|
2017-12-03 17:22:59 +03:00
|
|
|
|
|
|
|
bool Sync::setValume(unsigned int valume){
|
2018-01-09 22:14:54 +03:00
|
|
|
if(valume > 100 || !player->isSynced())
|
2017-12-03 17:22:59 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
player->setVolume(valume);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int Sync::getValume() const{
|
|
|
|
return player->volume();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int Sync::seek() const{
|
|
|
|
return player->position();
|
|
|
|
}
|
|
|
|
|
2017-12-03 23:08:43 +03:00
|
|
|
const QList<SongHeader>* Sync::getPlayList() const{
|
|
|
|
return &playList;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SongHeader* Sync::getCurentSong() const{
|
|
|
|
return curentSong;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 Sync::getEndPoint() const {
|
|
|
|
return player->duration();
|
|
|
|
}
|
|
|
|
|
2017-12-24 22:04:40 +03:00
|
|
|
int Sync::addNewSong(const QString &url){
|
|
|
|
int result = sql->save(url);
|
|
|
|
sql->updateAvailableSongs(playList);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-11-09 23:09:59 +03:00
|
|
|
Sync::~Sync(){
|
|
|
|
delete node;
|
|
|
|
delete player;
|
2017-12-25 18:48:43 +03:00
|
|
|
delete sql;
|
2017-11-22 20:05:53 +03:00
|
|
|
servers.clear();
|
2017-12-06 13:18:30 +03:00
|
|
|
|
2017-10-29 14:47:36 +03:00
|
|
|
}
|
2017-11-09 23:09:59 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-11-20 00:37:12 +03:00
|
|
|
|