Commit a433434e authored by Camilo Higuita's avatar Camilo Higuita

initial work on kde integration, mpris and knotify for desktop, on mobile ignored for now

parent b05f0867
......@@ -6,6 +6,12 @@ QT += websockets
QT += network
QT += xml
unix:!android:
{
include(kde/kde.pri)
}
CONFIG += c++11
include(android-openssl.pri)
......@@ -189,7 +195,10 @@ SOURCES += main.cpp \
taglib/fileref.cpp \
taglib/tag.cpp \
taglib/tagunion.cpp \
babe.cpp
babe.cpp \
RESOURCES += qml.qrc
......@@ -209,6 +218,7 @@ DISTFILES += \
db/script.sql \
android-openssl.pri \
# 3rdparty/kirigami/kirigami.pri
kde/kde.pri
HEADERS += \
......@@ -334,7 +344,11 @@ HEADERS += \
taglib/tagunion.h \
taglib/config.h \
taglib/taglib_config.h \
babe.h
babe.h \
#unix:!macx: LIBS += -L$$PWD/3rdparty/taglib/taglib/ -ltag
......
[Global]
IconName=preferences-system-bluetooth
Comment=Tiny Music Player
Name=Babe
[Event/Notify]
Name=Babe...
Comment=Connection to device failed
Icon=babe-qt
Action=Popup
......@@ -8,6 +8,12 @@
#include "settings/settings.h"
#include "pulpo/pulpo.h"
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
#include "kde/notify.h"
Notify *Babe::nof = new Notify;
#endif
using namespace BAE;
Babe::Babe(QObject *parent) : QObject(parent)
......@@ -23,6 +29,13 @@ Babe::Babe(QObject *parent) : QObject(parent)
}
Babe::~Babe()
{
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
delete Babe::nof;
#endif
}
QVariantList Babe::get(const QString &queryTxt)
{
return Babe::transformData(this->con->getDBData(queryTxt));
......@@ -152,6 +165,18 @@ int Babe::trackRate(const QString &path)
return this->con->getTrackStars(path);
}
void Babe::notify(const QString &title, const QString &body)
{
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
Babe::nof->notify(title, body);
#else
Q_UNUSED(title);
Q_UNUSED(body);
#endif
}
void Babe::scanDir(const QString &url)
{
emit this->set->collectionPathChanged({url});
......
......@@ -5,6 +5,11 @@
#include <QVariantList>
#include "utils/bae.h"
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
class Notify;
#endif
class CollectionDB;
class Pulpo;
class settings;
......@@ -17,7 +22,7 @@ class Babe : public QObject
Q_OBJECT
public:
explicit Babe(QObject *parent = nullptr);
~Babe();
/* DATABASE INTERFACES */
......@@ -34,7 +39,7 @@ public:
Q_INVOKABLE bool rateTrack(const QString &path, const int &value);
Q_INVOKABLE int trackRate(const QString &path);
Q_INVOKABLE static void notify(const QString &title, const QString &body);
/* SETTINGS */
Q_INVOKABLE void scanDir(const QString &url);
......@@ -60,11 +65,14 @@ public:
/*USEFUL*/
Q_INVOKABLE QString loadCover(const QString &url);
Q_INVOKABLE QVariantList searchFor(const QStringList &queries);
Q_INVOKABLE QVariantList searchFor(const QStringList &queries);
private:
CollectionDB *con;
settings *set;
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
static Notify *nof;
#endif
QString fetchCoverArt(DB &song);
static QVariantList transformData(const DB_LIST &dbList);
......
unix:linux:!android:
{
QT += dbus
QT += KConfigCore
QT += KNotifications
QT += KI18n
HEADERS += \ kde/notify.h \
kde/mpris2.h
SOURCES += kde/notify.cpp \
kde/mpris2.cpp
}
android:
{
QT -= dbus
QT -= KConfigCore
QT -= KNotifications
QT -= KI18n
HEADERS -= \ kde/notify.h \
kde/mpris2.h
SOURCES -= kde/notify.cpp \
kde/mpris2.cpp
}
/*
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 "mpris2.h"
#include<QDBusConnection>
#include <QDBusMessage>
static inline qlonglong convertTime(int t)
{
return t*1000000;
}
static QString mprisPath;
Mpris::Mpris(QObject *p)
: QObject(p)
, pos(-1)
{
QDBusConnection::sessionBus().registerService("org.mpris.MediaPlayer2.Babe");
QDBusConnection::sessionBus().registerObject("/org/mpris/MediaPlayer2", this, QDBusConnection::ExportAdaptors);
/*connect(this, SIGNAL(setRandom(bool)), MPDConnection::self(), SLOT(setRandom(bool)));
connect(this, SIGNAL(setRepeat(bool)), MPDConnection::self(), SLOT(setRepeat(bool)));
connect(this, SIGNAL(setSeekId(qint32, quint32)), MPDConnection::self(), SLOT(setSeekId(qint32, quint32)));
connect(this, SIGNAL(setVolume(int)), MPDConnection::self(), SLOT(setVolume(int)));*/
// connect(MPDConnection::self(), SIGNAL(currentSongUpdated(const Song &)), this, SLOT(updateCurrentSong(const Song &)));
//connect(MPDStatus::self(), SIGNAL(updated()), this, SLOT(updateStatus()));
/* if (mprisPath.isEmpty()) {
mprisPath=QLatin1String(CANTATA_REV_URL);
mprisPath.replace(".", "/");
mprisPath="/"+mprisPath+"/Track/%1";
}*/
//connect(CurrentCover::self(), SIGNAL(coverFile(const QString &)), this, SLOT(updateCurrentCover(const QString &)));
}
Mpris::~Mpris()
{
QDBusConnection::sessionBus().unregisterService("org.mpris.MediaPlayer2.cantata");
}
void Mpris::Pause()
{
qDebug()<<"pause";
}
void Mpris::Play()
{
qDebug()<<"play";
}
QString Mpris::PlaybackStatus() const
{
qDebug()<<"PlaybackStatus";
return "PlaybackStatus";
}
qlonglong Mpris::Position() const
{
// Cant use MPDStatus, as we dont poll for track position, but use a timer instead!
//return MPDStatus::self()->timeElapsed();
return 1000000000;
}
void Mpris::updateStatus()
{
QVariantMap map;
qDebug()<<"updateStatus";
}
void Mpris::updateCurrentCover(const QString &fileName)
{
if (fileName!=currentCover) {
currentCover=fileName;
signalUpdate("Metadata", Metadata());
}
}
void Mpris::updateCurrentSong()
{
qDebug()<<"updateCurrentSong";
}
QVariantMap Mpris::Metadata() const {
QVariantMap metadataMap;
return metadataMap;
}
void Mpris::Raise()
{
emit showMainWindow();
}
void Mpris::signalUpdate(const QString &property, const QVariant &value)
{
QVariantMap map;
map.insert(property, value);
signalUpdate(map);
}
void Mpris::signalUpdate(const QVariantMap &map)
{
if (map.isEmpty()) {
return;
}
QDBusMessage signal = QDBusMessage::createSignal("/org/mpris/MediaPlayer2",
"org.freedesktop.DBus.Properties",
"PropertiesChanged");
QVariantList args = QVariantList()
<< "org.mpris.MediaPlayer2.Player"
<< map
<< QStringList();
signal.setArguments(args);
QDBusConnection::sessionBus().send(signal);
}
/*
* Cantata
*
* Copyright (c) 2011-2016 Craig Drummond <craig.p.drummond@gmail.com>
*
* ----
*
* 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 2 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef MPRIS2_H
#define MPRIS2_H
#include<QObject>
#include <QObject>
#include <QStringList>
#include <QVariantMap>
#include <QApplication>
#include <QDebug>
class QDBusObjectPath;
class Mpris : public QObject
{
Q_OBJECT
// org.mpris.MediaPlayer2.Player
Q_PROPERTY( double Rate READ Rate WRITE SetRate )
Q_PROPERTY( qlonglong Position READ Position )
Q_PROPERTY( double MinimumRate READ MinimumRate )
Q_PROPERTY( double MaximumRate READ MaximumRate )
Q_PROPERTY( bool CanControl READ CanControl )
Q_PROPERTY( bool CanPlay READ CanPlay )
Q_PROPERTY( bool CanPause READ CanPause )
Q_PROPERTY( bool CanSeek READ CanSeek )
Q_PROPERTY( bool CanGoNext READ CanGoNext )
Q_PROPERTY( bool CanGoPrevious READ CanGoPrevious )
Q_PROPERTY( QString PlaybackStatus READ PlaybackStatus )
Q_PROPERTY( QString LoopStatus READ LoopStatus WRITE SetLoopStatus )
Q_PROPERTY( bool Shuffle READ Shuffle WRITE SetShuffle )
Q_PROPERTY( QVariantMap Metadata READ Metadata )
Q_PROPERTY( double Volume READ Volume WRITE SetVolume )
// org.mpris.MediaPlayer2
Q_PROPERTY( bool CanQuit READ CanQuit )
Q_PROPERTY( bool CanRaise READ CanRaise )
Q_PROPERTY( QString DesktopEntry READ DesktopEntry )
Q_PROPERTY( bool HasTrackList READ HasTrackList )
Q_PROPERTY( QString Identity READ Identity )
Q_PROPERTY( QStringList SupportedMimeTypes READ SupportedMimeTypes )
Q_PROPERTY( QStringList SupportedUriSchemes READ SupportedUriSchemes )
public:
Mpris(QObject *p);
virtual ~Mpris();
// org.mpris.MediaPlayer2.Player
void Next() { qDebug()<<"next"; }
void Previous() { qDebug()<<"previous"; }
void Pause();
void PlayPause() { qDebug()<<"pause"; }
void Stop() { qDebug()<<"stop"; }
void StopAfterCurrent() { qDebug()<<"stop after current"; }
void Play();
void Seek(qlonglong pos) { qDebug()<<pos; }
void SetPosition(const QDBusObjectPath &, qlonglong pos) { qDebug()<<pos; }
void OpenUri(const QString &) { }
QString PlaybackStatus() const;
QString LoopStatus() { return "sthm"; }
void SetLoopStatus(const QString &s) { emit setRepeat(QLatin1String("None")!=s); }
QVariantMap Metadata() const;
int Rate() const { return 1.0; }
void SetRate(double) { }
bool Shuffle() { return false; }
void SetShuffle(bool s) { emit setRandom(s); }
double Volume() const { return 100.0; }
void SetVolume(double v) { emit setVolume(v*100); }
qlonglong Position() const;
double MinimumRate() const { return 1.0; }
double MaximumRate() const { return 1.0; }
bool CanControl() const { return true; }
bool CanPlay() const { return true; }
bool CanPause() const { return true; }
bool CanSeek() const { return true; }
bool CanGoNext() const { return true; }
bool CanGoPrevious() const { return true; }
// org.mpris.MediaPlayer2
bool CanQuit() const { return true; }
bool CanRaise() const { return true; }
bool HasTrackList() const { return false; }
QString Identity() const { return QLatin1String("Cantata"); }
QString DesktopEntry() const {
#ifdef ENABLE_KDE_SUPPORT
// Desktop file is installed in $prefix/share/applications/kde4/
// rather than in $prefix/share/applications. The standard way to
// represent this dir is with a "kde4-" prefix. See:
// http://standards.freedesktop.org/menu-spec/1.0/go01.html#term-desktop-file-id
return QLatin1String("kde4-cantata");
#else
return QLatin1String("cantata");
#endif
}
QStringList SupportedUriSchemes() const { return QStringList(); }
QStringList SupportedMimeTypes() const { return QStringList(); }
public:
void updateCurrentSong();
public Q_SLOTS:
void Raise();
void Quit() { QApplication::quit(); }
Q_SIGNALS:
// org.mpris.MediaPlayer2.Player
void setRandom(bool toggle);
void setRepeat(bool toggle);
void setSeekId(qint32 songId, quint32 time);
void setVolume(int vol);
void showMainWindow();
public Q_SLOTS:
void updateCurrentCover(const QString &fileName);
private Q_SLOTS:
void updateStatus();
private:
void signalUpdate(const QString &property, const QVariant &value);
void signalUpdate(const QVariantMap &map);
private:
//MPDStatusValues status;
QString currentCover;
//Song currentSong;
int pos;
};
#endif // MPRIS2_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 "notify.h"
Notify::Notify(QObject *parent) : QObject(parent)
{}
Notify::~Notify()
{
qDebug()<<"DELETING KNOTIFY";
}
void Notify::notify(const QString &title, const QString &body)
{
// notification->setComponentName(QStringLiteral("Babe"));
auto notification = new KNotification(QStringLiteral("Notify"),KNotification::CloseOnTimeout, this);
connect(notification, &KNotification::closed, notification, &KNotification::deleteLater);
notification->setTitle(QStringLiteral("%1").arg(title));
notification->setText(QStringLiteral("%1").arg(body));
notification->sendEvent();
}
void Notify::notifySong(const BAE::DB &trackMap, const QPixmap &pix)
{
this->track = trackMap;
// notification->setComponentName(QStringLiteral("Babe"));
auto notification = new KNotification(QStringLiteral("Notify"),KNotification::CloseOnTimeout, this);
connect(notification, &KNotification::closed, notification, &KNotification::deleteLater);
notification->setTitle(QStringLiteral("%1").arg(track[BAE::KEY::TITLE]));
notification->setText(QStringLiteral("%1\n%2").arg(track[BAE::KEY::ARTIST],track[BAE::KEY::ALBUM]));
if(!pix.isNull()) notification->setPixmap(pix);
QStringList actions;
if(track[BAE::KEY::BABE].toInt()==1) actions<<i18n("Un-Babe it \xe2\x99\xa1");
else actions<<i18n("Babe it \xe2\x99\xa1");
actions<<i18n("Skip");
notification->setActions(actions);
connect(notification, SIGNAL(activated(uint)), SLOT(actions(uint)));
notification->sendEvent();
}
void Notify::actions(uint id)
{
switch(id)
{
case 1: emit this->babeSong(this->track); break;
case 2: emit this->skipSong(); break;
default: break;
}
}
#ifndef NOTIFY_H
#define NOTIFY_H
#include <QObject>
#include <QByteArray>
#include <klocalizedstring.h>
#include <knotifyconfig.h>
#include <knotification.h>
#include <QStandardPaths>
#include <QPixmap>
#include <QDebug>
#include <QMap>
#include "../utils/bae.h"
class Notify : public QObject
{
Q_OBJECT
public:
explicit Notify(QObject *parent = nullptr);
~Notify();
void notifySong(const BAE::DB &, const QPixmap &pix);
void notify(const QString &title, const QString &body);
private:
BAE::DB track;
signals:
void babeSong(const BAE::DB &track);
void skipSong();
public slots:
void actions(uint id);
};
#endif // NOTIFY_H
......@@ -44,6 +44,19 @@ ApplicationWindow
onClosing: Player.savePlaylist()
function runSearch()
{
if(searchInput.text)
{
var query = searchInput.text
var queries = query.split(",")
var res = bae.searchFor(queries)
searchView.populate(res)
// albumsView.filter(res)
currentView = 6
}
}
Connections
{
......@@ -104,43 +117,40 @@ ApplicationWindow
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
selectByMouse: !bae.isMobile()
// selectByMouseChanged: !bae.isMobile()
// canPaste: true
// canUndo: true
// canRedo: true
selectionColor: bae.hightlightColor()
selectedTextColor: bae.foregroundColor()
property string placeholderText: "Search..."
Label
// Label
// {
// text: searchInput.placeholderText
// visible: !(searchInput.focus || searchInput.text)
// horizontalAlignment: Text.AlignHCenter
// verticalAlignment: Text.AlignVCenter
// font.bold: true
// color: bae.foregroundColor()
// }
Icon
{
anchors.fill: parent
text: searchInput.placeholderText
anchors.centerIn: parent
visible: !(searchInput.focus || searchInput.text)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
id: searchBtn
text: MdiFont.Icon.magnify
color: bae.foregroundColor()
}
// onTextChanged:
// {
// if(searchInput.text.length===0)
// albumsView.populate()
// }
onAccepted:
{
var query = searchInput.text
var queries = query.split(",")
var res = bae.searchFor(queries)
searchView.populate(res)
// albumsView.filter(res)
currentView = 6
}
// onTextChanged:
// {
// if(searchInput.text.length===0)
// albumsView.populate()
// }
onAccepted: runSearch()
}
}
}
Rectangle
......
......@@ -30,5 +30,7 @@
<file>db/Queries.js</file>
<file>view_models/TableMenu.qml</file>
<file>widgets/SearchTable.qml</file>
<file>utils/Help.js</file>
<file>assets/Babe.notifyrc</file>
</qresource>
</RCC>
......@@ -39,14 +39,18 @@ settings::settings(QObject *parent) : QObject(parent)
qDebug() << "Getting settings info from: " << BAE::SettingPath;
qDebug() << "Getting artwork files from: " << BAE::CachePath;
#if defined(Q_OS_LINUX)
const auto notifyDir = BAE::NotifyDir;
if(!BAE::fileExists(notifyDir+"/Babe.notifyrc"))
{
qDebug()<<"The Knotify file does not exists, going to create it";
QFile knotify(":Data/data/Babe.notifyrc");
QFile knotify(":/assets/Babe.notifyrc");
if(knotify.copy(notifyDir+"/Babe.notifyrc"))
qDebug()<<"the knotify file got copied";
}
#endif
QDir collectionDBPath_dir(BAE::CollectionDBPath);
QDir cachePath_dir(BAE::CachePath);
......@@ -139,7 +143,7 @@ void settings::on_remove_clicked()
void settings::refreshCollectionPaths()
{
// auto queryTxt = QString("SELECT %1 FROM %2").arg(BAE::KEYMAP[BAE::KEY::URL], BAE::TABLEMAP[BAE::TABLE::SOURCES]);
// auto queryTxt = QString("SELECT %1 FROM %2").arg(BAE::KEYMAP[BAE::KEY::URL], BAE::TABLEMAP[BAE::TABLE::SOURCES]);
// for (auto track : this->connection->getDBData(queryTxt))
// {
......@@ -202,8 +206,8 @@ void settings::handleDirectoryChanged(const QString &dir)
void settings::checkCollection()
{
// this->refreshCollectionPaths();
// this->collectionWatcher();
// this->refreshCollectionPaths();
// this->collectionWatcher();
this->brainzOn = true;
this->startBrainz(1500);
}
......
......@@ -51,7 +51,6 @@ private:
bool brainzOn = false;
const QString notifyDir = BAE::NotifyDir;
QString pathToRemove;
......
function rootWidth()
{
return root.width;
}
function rootHeight()
{
return root.height;
}
......@@ -176,10 +176,13 @@ function babeTrack()
root.mainPlaylist.babeBtnIcon.text = Icon.heartOutline
root.mainPlaylist.babeBtnIcon.color = root.mainPlaylist.babeBtnIcon.defaultColor
}else
}else
{
bae.babeTrack(root.mainPlaylist.currentTrack.url, true)
root.mainPlaylist.babeBtnIcon.text = Icon.heartOutline
root.mainPlaylist.babeBtnIcon.color = "#E91E63"
root.mainPlaylist.babeBtnIcon.color = bae.babeColor()
bae.notify("Track Babe'd",root.mainPlaylist.currentTrack.title +" by "+ root.mainPlaylist.currentTrack.artist )
}
}
......@@ -3,6 +3,7 @@ import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../utils/Icons.js" as MdiFont
import "../utils/Help.js" as H
import "../utils"
Menu
......