diff options
5 files changed, 545 insertions, 0 deletions
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp new file mode 100644 index 00000000..667ebefb --- /dev/null +++ b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp @@ -0,0 +1,178 @@ +//=========================================== +// Lumina-Desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "PianoBarProcess.h" + +#include <QTime> +#include <QDir> +#include <QFile> +#include <QTextStream> + +#include <LUtils.h> + +PianoBarProcess::PianoBarProcess(QWidget *parent) : QObject(parent){ + setupProcess(); + +} + +PianoBarProcess::~PianoBarProcess(){ + +} + +// ===== PUBLIC ====== +//Interaction functions +bool PianoBarProcess::isSetup(); //email/password already saved for use or not +void PianoBarProcess::setLogin(QString email, QString pass); +void PianoBarProcess::closePianoBar(); //"q" + +QString PianoBarProcess::currentStation(); //Re-direct for the "autostartStation()" function; +QStringList PianoBarProcess::stations(); +void PianoBarProcess::setCurrentStation(QString station); + +void PianoBarProcess::deleteCurrentStation(); //"d" +void PianoBarProcess::createNewStation(); //"c" +void PianoBarProcess::createStationFromCurrentSong(); //"v" +void PianoBarProcess::changeStation(); //"s" + +//Settings Manipulation +QString PianoBarProcess::audioQuality(){ // "audio_quality" = [low, medium, high] + +} + +void PianoBarProcess::setAudioQuality(QString); // [low, medium, high] +QString PianoBarProcess::autostartStation(); //"autostart_station" = ID +void PianoBarProcess::setAutostartStation(QString); +QString PianoBarProcess::proxy(); //"proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" ) +void PianoBarProcess::setProxy(QString); +QString PianoBarProcess::controlProxy(); //"control_proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" ) +void PianoBarProcess::setControlProxy(QString); + +// ====== PUBLIC SLOTS ====== +void PianoBarProcess::play(); // "P" +void PianoBarProcess::pause(); //"S" + +void PianoBarProcess::volumeDown(); //"(" +void PianoBarProcess::volumeUp(); //")" + +void PianoBarProcess::skipSong(); //"n" +void PianoBarProcess::loveSong(); // "+" +void PianoBarProcess::tiredSong(); // "t" +void PianoBarProcess::banSong(); //"-" +void PianoBarProcess::bookmarkSong(); //"b" + +void PianoBarProcess::explainSong(); //"e" + +void PianoBarProcess::requestHistory(); // "h" +void PianoBarProcess::requestSongInfo(); //"i" +void PianoBarProcess::requestUpcoming(); //"u" + +// ====== PRIVATE ====== +void PianoBarProcess::GenerateSettings(){ + currentSettings << "audio_quality = medium"; + currentSettings << "autoselect = 1"; //automatically select the last item in a list (station selection only) + currentSettings << "format_list_song = %r::::%t::::%a"; //[rating, title, artist] + currentSettings << "format_nowplaying_song = %r::::%t::::%a::::%l::::%u::::%s"; // [rating, title, artist, album, details url, station (if not quickmix)] + currentSettings << "format_nowplaying_station = %n::::%i"; //[name, id] +} + +void PianoBarProcess::loadSettings(){ + currentSettings.clear(); + QFile file(settingspath); + if(!file.exists()){ return; } + if(file.open(QIODevice::ReadOnly)){ + QTextStream in(&file); + currentSettings = in.readAll().split("\n"); + file.close(); + } +} + +QString PianoBarProcess::settingValue(QString var){ + for(int i=0; i<currentSettings.length(); i++){ + if(currentSettings[i].startsWith(var+" = ")){ return currentSettings[i].section(" = ", 1,-1); } + } + return ""; +} + +void PianoBarProcess::setSettingValue(QString var,QString val){ + bool changed = false; + for(int i=0; i<currentSettings.length() && !changed; i++){ + if(currentSettings[i].startsWith(var+" = ")){ currentSettings[i] = var+" = "+val; changed = true; } + } + if(!changed){ currentSettings << var+" = "+val; } +} + +void PianoBarProcess::saveSettingsFile(){ + //Ensure the parent directory exists first + QDir dir(settingspath.section("/",0,-2)); + if(!dir.exists()){ dir.mkpath(dir.absolutePath()); } + //Now save the settings + QFile file(settingspath); + if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + QTextStream out(&file); + out << currentSettings.join("\n"); + file.close(); + } +} + +void PianoBarProcess::setupProcess(){ + PROC = new QProcess(this); + //Ensure this process always points to the right configuration directory/files + QString configdir = getenv("XDG_CONFIG_HOME"); + if(configdir.isEmpty()){ configdir = QDir::homePath()+"/.config/lumina-desktop"; } + else{ configdir.append("/lumina-desktop"); } + QProcessEnvironment penv; + penv.insert("XDG_CONFIG_HOME",configdir); + settingspath = configdir+"/pianobar/config"; + PROC->setProcessEnvironment(penv); + //Now setup the rest of the process + PROC->setProcessChannelMode(QProcess::MergedChannels); + QString bin = "pianobar"; + LUtils::isValidBinary(bin); //will change "bin" to the full path + PROC->setProgram(bin); + connect(PROC, SIGNAL(readyRead()), this, SLOT(ProcUpdate()) ); +} + +// ====== PRIVATE SLOTS ====== +void PianoBarProcess::ProcUpdate(){ + QStringList info = QString(PROC->readAllStandardOutput()).split("\n"); + //NOTE: Need to have a cache of info lines which can carry over between updates as needed (for questions, etc) + qDebug() << "Got Update:" << info; + for(int i=0; i<info.length(); i++){ + if(info[i].startsWith("|>")){ + //Now playing line (station, or song) + QStringList data = info[i].section(">",1,-1).simplified().split("::::"); //Make sure to chop the line prefix off first + if(data.length()==2){ //station + cstation = data[0]; //save the name for later + emit NowPlayingStation(data[0], data[1]); + //Automatically save this station for autostart next time (make toggle-able later) + if(data[1]!=autostartStation()){ setAutostartStation(data[1]); } + + }else if(data.length()==6){ //song + emit NowPlayingSong( data[0]=="<3", data[1], data[2], data[3], data[4], data[5] ); + } + }else if(info[i].startsWith("(i) ")){ //informational line + emit NewInformation(info[i].section(" ",1,-1)); + }else if(info[i].startsWith("[?] ")){ //waiting for reply to question + if(info[i].contains("Select Station:"){ + //Find the number before this line which corresponds to the cstation variable/name + for(j=i-1; j>=0; j--){ + if(info[j].contains(")" && info[j].contains(cstation) ){ + PROC->write(info[j].section(")",0,0).simplified() + "\r\n"); + break; + } + } + } + + }else if(info[i].startsWith("#")){ + //Time Stamp + QTime stamp = QTime::fromString(info[i].section("/",0,0).section("-",1,-1), "mm:ss"); + int curS = 60*stamp.minutes() + stamp.seconds(); //time remaining + stamp = QTime::fromString(info[i].section("/",1,-1), "mm:ss"); + int totS = 60*stamp.minutes() + stamp.sections(); //time total + emit TimeUpdate(totS-curS, totS); + } + } +} diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h new file mode 100644 index 00000000..83404e0c --- /dev/null +++ b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h @@ -0,0 +1,103 @@ +//=========================================== +// Lumina-Desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is a interface to the "pianobar" utility for streaming +// audio from the Pandora radio service +//=========================================== +#ifndef _LUMINA_PIANOBAR_PROCESS_H +#define _LUMINA_PIANOBAR_PROCESS_H + +#include <QObject> +#include <QWidget> +#include <QProcess> + + +// #define PIANOBAR_FIFO QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/pianobar/ctl" +// #define PIANOBAR_CONFIG QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/pianobar/config" + +class PianoBarProcess : public QObject{ + Q_OBJECT +public: + enum State {Stopped, Running, Paused}; + + PianoBarProcess(QWidget *parent); + ~PianoBarProcess(); + + State currentState(); + + //Interaction functions + bool isSetup(); //email/password already saved for use or not + void setLogin(QString email, QString pass); + void closePianoBar(); //"q" + + QString currentStation(); //Re-direct for the "autostartStation()" function; + QStringList stations(); + void setCurrentStation(QString station); + + void deleteCurrentStation(); //"d" + void createNewStation(); //"c" + void createStationFromCurrentSong(); //"v" + void changeStation(); //"s" + + //Settings Manipulation + QString audioQuality(); // "audio_quality" = [low, medium, high] + void setAudioQuality(QString); // [low, medium, high] + QString autostartStation(); //"autostart_station" = ID + void setAutostartStation(QString); + QString proxy(); //"proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" ) + void setProxy(QString); + QString controlProxy(); //"control_proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" ) + void setControlProxy(QString); + +public slots: + void play(); // "P" + void pause(); //"S" + + void volumeDown(); //"(" + void volumeUp(); //")" + + void skipSong(); //"n" + void loveSong(); // "+" + void tiredSong(); // "t" + void banSong(); //"-" + void bookmarkSong(); //"b" + + void explainSong(); //"e" + + void requestHistory(); // "h" + void requestSongInfo(); //"i" + void requestUpcoming(); //"u" + + +private: + //Process + QProcess PROC; + void setupProcess(); + + //Settings file management + QStringList currentSettings; //cache of the settings file (file is really small); + QString settingsPath; //location of the settings file + void GenerateSettings(); + void loadSettings(); + QString settingValue(QString); + void setSettingValue(QString,QString); + void saveSettingsFile(); + + //Cached Info + QString cstation; //current station + QStringList stationNames; + +private slots: + void ProcUpdate(); + + +signals: + void NewInformation(QString); //random status updates/information + void NowPlayingStation(QString, QString); //[name, id] + void NowPlayingSong(bool, QString,QString,QString, QString, QString); //[isLoved, title, artist, album, detailsURL, fromStation] + void TimeUpdate(int, int); //[current secs, total secs]; +}; +#endif diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.desktop b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.desktop new file mode 100644 index 00000000..180f4562 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Exec=lumina-mediaplayer %f +Icon=audio-x-generic +Terminal=false +Type=Application +StartupNotify=true +Categories=Utility; +MimeType= +Name=Lumina Media Player +Comment=Play Multimedia Content diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro new file mode 100644 index 00000000..7d91b770 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro @@ -0,0 +1,97 @@ +include("$${PWD}/../../OS-detect.pri") + +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets concurrent + + +TARGET = lumina-mediaplayer +TEMPLATE = app + + +target.path = $${L_BINDIR} + +#include all the special classes from the Lumina tree +include(../../core/libLumina/LUtils.pri) #includes LUtils +include(../../core/libLumina/LuminaXDG.pri) + +SOURCES += main.cpp\ + mainUI.cpp + +HEADERS += mainUI.h + +FORMS += mainUI.ui + +TRANSLATIONS = i18nl-mediap_af.ts \ + i18nl-mediap_ar.ts \ + i18nl-mediap_az.ts \ + i18nl-mediap_bg.ts \ + i18nl-mediap_bn.ts \ + i18nl-mediap_bs.ts \ + i18nl-mediap_ca.ts \ + i18nl-mediap_cs.ts \ + i18nl-mediap_cy.ts \ + i18nl-mediap_da.ts \ + i18nl-mediap_de.ts \ + i18nl-mediap_el.ts \ + i18nl-mediap_en_GB.ts \ + i18nl-mediap_en_ZA.ts \ + i18nl-mediap_es.ts \ + i18nl-mediap_et.ts \ + i18nl-mediap_eu.ts \ + i18nl-mediap_fa.ts \ + i18nl-mediap_fi.ts \ + i18nl-mediap_fr.ts \ + i18nl-mediap_fr_CA.ts \ + i18nl-mediap_gl.ts \ + i18nl-mediap_he.ts \ + i18nl-mediap_hi.ts \ + i18nl-mediap_hr.ts \ + i18nl-mediap_hu.ts \ + i18nl-mediap_id.ts \ + i18nl-mediap_is.ts \ + i18nl-mediap_it.ts \ + i18nl-mediap_ja.ts \ + i18nl-mediap_ka.ts \ + i18nl-mediap_ko.ts \ + i18nl-mediap_lt.ts \ + i18nl-mediap_lv.ts \ + i18nl-mediap_mk.ts \ + i18nl-mediap_mn.ts \ + i18nl-mediap_ms.ts \ + i18nl-mediap_mt.ts \ + i18nl-mediap_nb.ts \ + i18nl-mediap_nl.ts \ + i18nl-mediap_pa.ts \ + i18nl-mediap_pl.ts \ + i18nl-mediap_pt.ts \ + i18nl-mediap_pt_BR.ts \ + i18nl-mediap_ro.ts \ + i18nl-mediap_ru.ts \ + i18nl-mediap_sk.ts \ + i18nl-mediap_sl.ts \ + i18nl-mediap_sr.ts \ + i18nl-mediap_sv.ts \ + i18nl-mediap_sw.ts \ + i18nl-mediap_ta.ts \ + i18nl-mediap_tg.ts \ + i18nl-mediap_th.ts \ + i18nl-mediap_tr.ts \ + i18nl-mediap_uk.ts \ + i18nl-mediap_uz.ts \ + i18nl-mediap_vi.ts \ + i18nl-mediap_zh_CN.ts \ + i18nl-mediap_zh_HK.ts \ + i18nl-mediap_zh_TW.ts \ + i18nl-mediap_zu.ts + +dotrans.path=$${L_SHAREDIR}/lumina-desktop/i18n/ +dotrans.extra=cd i18n && $${LRELEASE} -nounfinished *.ts && cp *.qm $(INSTALL_ROOT)$${L_SHAREDIR}/lumina-desktop/i18n/ + +desktop.files=lumina-mediaplayer.desktop +desktop.path=$${L_SHAREDIR}/applications/ + +INSTALLS += target desktop + +WITH_I18N{ + INSTALLS += dotrans +} diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui new file mode 100644 index 00000000..d662b20c --- /dev/null +++ b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>385</width> + <height>410</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="frame_type"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QRadioButton" name="radio_local"> + <property name="text"> + <string>Local Files</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radio_pandora"> + <property name="text"> + <string>Pandora Radio</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="stackedWidget"> + <widget class="QWidget" name="page_local"/> + <widget class="QWidget" name="page_pandora"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_pandora_playing"> + <attribute name="title"> + <string>Now Playing</string> + </attribute> + </widget> + <widget class="QWidget" name="tab_pandora_settings"> + <attribute name="title"> + <string>Settings</string> + </attribute> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>385</width> + <height>22</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <widget class="QToolBar" name="toolBar"> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <property name="movable"> + <bool>false</bool> + </property> + <property name="allowedAreas"> + <set>Qt::TopToolBarArea</set> + </property> + <property name="floatable"> + <bool>false</bool> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionPlay"/> + <addaction name="actionPause"/> + <addaction name="actionStop"/> + <addaction name="actionNext"/> + <addaction name="actionBack"/> + <addaction name="actionVolUp"/> + <addaction name="actionVolDown"/> + </widget> + <action name="actionPlay"> + <property name="text"> + <string>Play</string> + </property> + </action> + <action name="actionPause"> + <property name="text"> + <string>Pause</string> + </property> + </action> + <action name="actionStop"> + <property name="text"> + <string>Stop</string> + </property> + </action> + <action name="actionNext"> + <property name="text"> + <string>Next</string> + </property> + </action> + <action name="actionBack"> + <property name="text"> + <string>Back</string> + </property> + </action> + <action name="actionVolUp"> + <property name="text"> + <string>VolUp</string> + </property> + </action> + <action name="actionVolDown"> + <property name="text"> + <string>VolDown</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> |