Commit c0190216 authored by Camilo Higuita's avatar Camilo Higuita

initial work on database

parent 4fa77346
QT += quick multimedia sql
QT += quick multimedia sql widgets
CONFIG += c++11
unix:!macx: LIBS += -L$$PWD/3rdparty/taglib-1.9.1/taglib/ -ltag
INCLUDEPATH += $$PWD/3rdparty/taglib-1.9.1/taglib/Headers
DEPENDPATH += $$PWD/3rdparty/taglib-1.9.1/taglib/Headers
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
......@@ -13,7 +18,9 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp \
db/collectionDB.cpp
db/collectionDB.cpp \
settings/settings.cpp \
services/local/taginfo.cpp
RESOURCES += qml.qrc
......@@ -28,8 +35,13 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
DISTFILES +=
DISTFILES += \
db/script.sql
HEADERS += \
db/collectionDB.h \
utils/bae.h
utils/bae.h \
settings/settings.h \
settings/fileloader.h \
services/local/taginfo.h
......@@ -39,6 +39,12 @@ CollectionDB::~CollectionDB()
this->m_db.close();
}
void CollectionDB::test()
{
qDebug()<<"call form qml";
emit qmlSignal("lalala");
}
void CollectionDB::closeConnection()
{
qDebug()<<"CLOSING COLLECTIONDB";
......@@ -48,7 +54,7 @@ void CollectionDB::prepareCollectionDB() const
{
QSqlQuery query(this->m_db);
QFile file(":/Data/src/db/script.sql");
QFile file(":/db/script.sql");
if (!file.exists())
{
......
......@@ -28,6 +28,7 @@ public:
explicit CollectionDB(QObject *parent = nullptr);
~CollectionDB() override;
bool execQuery(QSqlQuery &query) const;
bool execQuery(const QString &queryTxt);
......@@ -115,7 +116,7 @@ private:
public slots:
void closeConnection();
/*useful*/
void test();
signals:
void trackInserted();
......@@ -123,6 +124,8 @@ signals:
void DBactionFinished();
void albumsCleaned(const int &amount);
void artistsCleaned(const int &amount);
void qmlSignal(QString str);
};
#endif // COLLECTION_H
CREATE TABLE ARTISTS
(
artist TEXT ,
artwork TEXT ,
wiki TEXT,
PRIMARY KEY(artist)
) ;
CREATE TABLE ALBUMS
(
album TEXT ,
artist TEXT,
artwork TEXT,
wiki TEXT,
PRIMARY KEY(album, artist),
FOREIGN KEY(artist) REFERENCES artists(artist)
) ;
CREATE TABLE TAGS
(
tag TEXT NOT NULL,
context TEXT NOT NULL,
PRIMARY KEY(tag, context)
) ;
CREATE TABLE MOODS
(
mood TEXT PRIMARY KEY
) ;
CREATE TABLE PLAYLISTS
(
playlist TEXT PRIMARY KEY ,
addDate DATE NOT NULL
) ;
CREATE TABLE SOURCES_TYPES
(
id INTEGER PRIMARY KEY ,
name TEXT NOT NULL
) ;
CREATE TABLE SOURCES
(
url TEXT PRIMARY KEY ,
SOURCE_TYPES_id INTEGER NOT NULL,
FOREIGN KEY(SOURCE_TYPES_id) REFERENCES SOURCES_TYPES(id)
) ;
CREATE TABLE TRACKS
(
url TEXT ,
sources_url TEXT ,
track INTEGER ,
title TEXT NOT NULL,
artist TEXT NOT NULL,
album TEXT NOT NULL,
duration INTEGER ,
comment TEXT,
played INTEGER ,
babe INTEGER NOT NULL,
stars INTEGER NOT NULL,
releaseDate DATE ,
addDate DATE NOT NULL,
lyrics TEXT NOT NULL,
genre TEXT,
art TEXT,
wiki TEXT NOT NULL,
PRIMARY KEY (url),
FOREIGN KEY(sources_url) REFERENCES SOURCES(url),
FOREIGN KEY(album, artist) REFERENCES albums(album, artist)
) ;
CREATE TABLE TRACKS_MOODS
(
mood TEXT NOT NULL ,
url TEXT NOT NULL ,
FOREIGN KEY(mood) REFERENCES MOODS(mood),
FOREIGN KEY(url) REFERENCES TRACKS(url)
) ;
CREATE TABLE TRACKS_TAGS
(
tag TEXT NOT NULL ,
context TEXT NOT NULL ,
url TEXT NOT NULL ,
PRIMARY KEY (tag, context, url),
FOREIGN KEY(tag, context) REFERENCES TAGS(tag, context),
FOREIGN KEY(url) REFERENCES TRACKS(url)
) ;
CREATE TABLE ARTISTS_TAGS
(
tag TEXT NOT NULL ,
context TEXT NOT NULL,
artist TEXT NOT NULL ,
PRIMARY KEY (tag, context, artist),
FOREIGN KEY(tag, context) REFERENCES TAGS(tag, context),
FOREIGN KEY(artist) REFERENCES ARTISTS(artist)
) ;
CREATE TABLE ALBUMS_TAGS
(
tag TEXT NOT NULL ,
context TEXT NOT NULL,
album TEXT NOT NULL ,
artist TEXT NOT NULL,
PRIMARY KEY (tag, context, album, artist),
FOREIGN KEY(tag, context) REFERENCES TAGS(tag, context),
FOREIGN KEY(album, artist) REFERENCES ALBUMS(album, artist)
) ;
CREATE TABLE PLAYLISTS_MOODS
(
playlist TEXT NOT NULL ,
mood TEXT NOT NULL ,
PRIMARY KEY (playlist, mood),
FOREIGN KEY(playlist) REFERENCES PLAYLISTS(playlist),
FOREIGN KEY(mood) REFERENCES MOODS(mood)
) ;
CREATE TABLE TRACKS_PLAYLISTS
(
playlist TEXT NOT NULL ,
url TEXT NOT NULL ,
addDate DATE NOT NULL,
PRIMARY KEY (playlist, url),
FOREIGN KEY(playlist) REFERENCES PLAYLISTS(playlist),
FOREIGN KEY(url) REFERENCES TRACKS(url)
) ;
CREATE TABLE LOG
(
id INTEGER NOT NULL,
retrieval_date DATE NOT NULL,
PRIMARY KEY(id)
);
--First insertions
INSERT INTO SOURCES_TYPES VALUES (1,"LOCAL");
INSERT INTO SOURCES_TYPES VALUES (2,"ONLINE");
INSERT INTO SOURCES_TYPES VALUES (3,"DEVICE");
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QFontDatabase>
#include <QQmlContext>
#include <QApplication>
#include "db/collectionDB.h"
#include "utils/bae.h"
#include "settings/settings.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QApplication app(argc, argv);
QFontDatabase::addApplicationFont(":/utils/materialdesignicons-webfont.ttf");
qmlRegisterType<CollectionDB>("org.babe.qml", 1, 0, "CON");
QQmlApplicationEngine engine;
auto context = engine.rootContext();
CollectionDB con;
settings settings;
context->setContextProperty("con", &con);
context->setContextProperty("set", &settings);
qmlRegisterUncreatableMetaObject(BAE::staticMetaObject,
"com.babe.bae", 1, 0, "BAE",
"Cannot create namespace WarningLevel in QML");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
......
......@@ -24,6 +24,12 @@ Kirigami.ApplicationWindow
pageStack.defaultColumnWidth: columnWidth
pageStack.initialPage: [playlist, views]
Connections
{
target: con
onQmlSignal: console.log("lalaland")
}
header: BabeBar
{
id: mainToolbar
......@@ -36,7 +42,10 @@ Kirigami.ApplicationWindow
onArtistsViewClicked: currentView = 2
onPlaylistsViewClicked: currentView = 3
onInfoViewClicked: currentView = 4
onPlaylistClicked: currentIndex = -1
onPlaylistClicked: {
con.test()
console.log(BAE.SettingPath)
}
}
......@@ -108,7 +117,7 @@ Kirigami.ApplicationWindow
ToolButton
{
id: previousBtn
Icon{text: MdiFont.Icon.skipPrevious}
Icon {text: MdiFont.Icon.skipPrevious}
}
ToolButton
......@@ -156,7 +165,6 @@ Kirigami.ApplicationWindow
Page
{
width: parent.width /2
height: parent.height
clip: true
......@@ -186,6 +194,10 @@ Kirigami.ApplicationWindow
{
}
SettingsView
{
}
onCurrentIndexChanged:
{
currentView = currentIndex
......
......@@ -19,5 +19,7 @@
<file>data_models/db_model.qml</file>
<file>widgets/MainPlaylist.qml</file>
<file>assets/test.jpg</file>
<file>db/script.sql</file>
<file>widgets/SettingsView.qml</file>
</qresource>
</RCC>
#include "socket.h"
#include "QtWebSockets/qwebsocketserver.h"
#include "QtWebSockets/qwebsocket.h"
#include <QtCore/QDebug>
QT_USE_NAMESPACE
Socket::Socket(quint16 port, QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Babe Server"),
QWebSocketServer::NonSecureMode, this))
{
if (this->m_pWebSocketServer->listen(QHostAddress::Any, port))
{
qDebug() << "Babe listening on port" << port;
connect(this->m_pWebSocketServer, &QWebSocketServer::newConnection,
this, &Socket::onNewConnection);
connect(this->m_pWebSocketServer, &QWebSocketServer::closed, this, &Socket::closed);
}
}
Socket::~Socket()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
void Socket::sendMessageTo(const int &client, const QString &message)
{
if(this->m_clients.isEmpty() && this->m_clients.size()>=client)
return;
auto s_client = this->m_clients.at(client);
s_client->sendTextMessage(message);
}
void Socket::onNewConnection()
{
qDebug()<<"trying new connection";
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &Socket::processTextMessage);
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &Socket::processBinaryMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Socket::socketDisconnected);
m_clients << pSocket;
emit this->connected(m_clients.size()-1);
}
void Socket::processTextMessage(const QString &message)
{
emit this->message(message);
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
qDebug() << "Message received:" << message;
if (pClient)
{
pClient->sendTextMessage(message);
}
}
void Socket::processBinaryMessage(QByteArray message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
qDebug() << "Binary Message received:" << message;
if (pClient) {
pClient->sendBinaryMessage(message);
}
}
void Socket::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
qDebug() << "socketDisconnected:" << pClient;
if (pClient) {
emit this->disconnected(pClient->origin());
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
#ifndef SOCKET_H
#define SOCKET_H
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QByteArray>
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class Socket : public QObject
{
Q_OBJECT
public:
explicit Socket(quint16 port, QObject *parent = Q_NULLPTR);
~Socket();
void sendMessageTo(const int &client, const QString &message);
Q_SIGNALS:
void closed();
void disconnected(const QString &id);
void connected(const int &index);
void message(const QString &message);
private Q_SLOTS:
void onNewConnection();
void processTextMessage(const QString &message);
void processBinaryMessage(QByteArray message);
void socketDisconnected();
private:
QWebSocketServer *m_pWebSocketServer;
QList<QWebSocket *> m_clients;
};
#endif // SOCKET_H
/*
Babe - tiny music player
Copyright (C) 2017 Camilo Higuita
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.
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, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "taginfo.h"
#include "../../utils/bae.h"
using namespace BAE;
TagInfo::TagInfo(const QString &url)
{
this->file = TagLib::FileRef(url.toUtf8());
this->path = url;
}
TagInfo::~TagInfo(){}
QString TagInfo::getAlbum() const
{
return !QString::fromStdWString(file.tag()->album().toWString()).isEmpty()
? QString::fromStdWString(file.tag()->album().toWString())
: SLANG[W::UNKNOWN];
}
QString TagInfo::getTitle() const
{
return !QString::fromStdWString(file.tag()->title().toWString()).isEmpty()
? QString::fromStdWString(file.tag()->title().toWString())
: fileName();
}
QString TagInfo::getArtist() const
{
return QString::fromStdWString(file.tag()->artist().toWString()).size() > 0
? QString::fromStdWString(file.tag()->artist().toWString())
: SLANG[W::UNKNOWN];
}
int TagInfo::getTrack() const { return static_cast<signed int>(file.tag()->track()); }
QString TagInfo::getGenre() const
{
return QString::fromStdWString(file.tag()->genre().toWString()).size() > 0
? QString::fromStdWString(file.tag()->genre().toWString())
: SLANG[W::UNKNOWN];
}
QString TagInfo::fileName() const
{
return BAE::getNameFromLocation(path);
}
uint TagInfo::getYear() const
{
//return BAE::getNameFromLocation(path);
return file.tag()->year();
}
int TagInfo::getDuration() const
{
return file.audioProperties()->lengthInSeconds();
}
QString TagInfo::getComment() const
{
return QString::fromStdWString(file.tag()->comment().toWString()).size() > 0
? QString::fromStdWString(file.tag()->genre().toWString())
: SLANG[W::UNKNOWN];
}
QByteArray TagInfo::getCover() const
{
QByteArray array;
return array;
}
void TagInfo::setCover(const QByteArray &array)
{
Q_UNUSED(array);
}
void TagInfo::setComment(const QString &comment)
{
this->file.tag()->setComment(comment.toStdString());
this->file.save();
}
void TagInfo::setAlbum(const QString &album)
{
this->file.tag()->setAlbum(album.toStdString());
this->file.save();
}
void TagInfo::setTitle(const QString &title)
{
this->file.tag()->setTitle(title.toStdString());
this->file.save();
}
void TagInfo::setTrack(const int &track)
{
this->file.tag()->setTrack(static_cast<unsigned int>(track));
this->file.save();
}
void TagInfo::setArtist(const QString &artist)
{
this->file.tag()->setArtist(artist.toStdString());
this->file.save();
}
void TagInfo::setGenre(const QString &genre)
{
this->file.tag()->setGenre(genre.toStdString());
this->file.save();
}
#ifndef TAGINFO_H
#define TAGINFO_H
#include <taglib/taglib.h>
#include <taglib/tag.h>
#include <taglib/fileref.h>
#include <taglib/mp4properties.h>
#include <taglib/mp4tag.h>
#include <taglib/mp4file.h>
#include <taglib/mp4coverart.h>
#include <taglib/id3v2tag.h>
#include <QString>
#include <QByteArray>
class TagInfo
{
public:
TagInfo(const QString &url);
~TagInfo();
QString getAlbum() const;
QString getTitle() const;
QString getArtist() const;
int getTrack() const;
QString getGenre() const;
QString fileName() const;
QString getComment() const;
QByteArray getCover() const;
int getDuration() const;
uint getYear() const;
void setAlbum(const QString &album) ;
void setTitle(const QString &title);
void setTrack(const int &track);
void setArtist(const QString &artist);
void setGenre(const QString &genre);
void setComment(const QString &comment);
void setCover(const QByteArray &array);
private:
TagLib::FileRef file;
QString path;
};
#endif // TAGINFO_H
/*
Babe - tiny music player
Copyright (C) 2017 Camilo Higuita
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.
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, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "youtube.h"
#include "../../pulpo/pulpo.h"
#include "../../kde/notify.h"
#include "../../views/babewindow.h"
#include "../../db/collectionDB.h"
using namespace BAE;
YouTube::YouTube(QObject *parent) : QObject(parent) {}
YouTube::~YouTube(){}
void YouTube::fetch(const QString &json)
{
QJsonParseError jsonParseError;
auto jsonResponse = QJsonDocument::fromJson(json.toUtf8(), &jsonParseError);
if (jsonParseError.error != QJsonParseError::NoError) return;
if (!jsonResponse.isObject()) return;
QJsonObject mainJsonObject(jsonResponse.object());
auto data = mainJsonObject.toVariantMap();
auto id = data.value("id").toString().trimmed();
auto title = data.value("title").toString().trimmed();
auto artist = data.value("artist").toString().trimmed();
auto album = data.value("album").toString().trimmed();
auto playlist = data.value("playlist").toString().trimmed();
auto page = data.value("page").toString().replace('"',"").trimmed();
qDebug()<< id << title << artist;
DB infoMap;
infoMap.insert(KEY::TITLE, title);
infoMap.insert(KEY::ARTIST, artist);
infoMap.insert(KEY::ALBUM, album);
infoMap.insert(KEY::URL, page);
infoMap.insert(KEY::ID, id);
infoMap.insert(KEY::PLAYLIST, playlist);
if(!this->ids.contains(infoMap[KEY::ID]))
{
this->ids << infoMap[KEY::ID];
auto process = new QProcess(this);
process->setWorkingDirectory(YoutubeCachePath);
//connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(processFinished()));
//connect(process, SIGNAL(finished(int)), this, SLOT(processFinished_totally(int)));
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus)
{
// qDebug()<<"processFinished_totally"<<exitCode<<exitStatus;
processFinished_totally(exitCode, infoMap, exitStatus);
process->deleteLater();
});
BabeWindow::nof->notify("Song received!", infoMap[KEY::TITLE]+ " - "+ infoMap[KEY::ARTIST]+".\nWait a sec while the track is added to your collection :)");
auto command = ydl;
command = command.replace("$$$",infoMap[KEY::URL])+" "+infoMap[KEY::ID];
qDebug()<<command;
process->start(command);
}
}
void YouTube::processFinished_totally(const int &state,const DB &info,const QProcess::ExitStatus &exitStatus)
{
auto track = info;
auto doneId = track[KEY::ID];
auto file = YoutubeCachePath+track[KEY::URL]+".m4a";
ids.removeAll(doneId);
track.insert(KEY::URL,file);
qDebug()<<track[KEY::ID]<<track[KEY::TITLE]<<track[KEY::ARTIST]<<track[KEY::PLAYLIST]<<track[KEY::URL];
/*here get metadata*/
if(exitStatus == QProcess::NormalExit)
{