1
0
Fork 0

[Tidy] Tidyed up things, removed QML Reloading and Discord support.

This commit is contained in:
NamedKitten 2018-12-06 08:13:14 +00:00
parent 5be24ac560
commit b6d5547453
25 changed files with 39 additions and 902 deletions

View file

@ -4,21 +4,12 @@ project(KittehPlayer)
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
set(CMAKE_AUTOMOC ON)
option(DEVELOP "Enable runtime QML reloading for developing." OFF)
option(DISCORD "Enable Discord SDK." OFF)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5 CONFIG REQUIRED COMPONENTS Qml Quick Gui Widgets Core X11Extras)
find_package(Qt5QuickCompiler)
if(DEVELOP)
qt5_add_resources(QT_RESOURCES qml.qrc)
else()
qtquick_compiler_add_resources(qml_QRC src/qml/qml.qrc)
endif()
find_package(PkgConfig)
pkg_check_modules(MPV REQUIRED mpv)
@ -29,7 +20,6 @@ if(X11_FOUND AND Xext_FOUND)
add_definitions(-DENABLE_X11)
endif(X11_FOUND AND Xext_FOUND)
set(SOURCES
src/main.cpp
src/DirectMpvPlayerBackend.cpp
@ -37,14 +27,13 @@ set(SOURCES
src/enums.hpp
)
if(MPV_VERSION VERSION_GREATER_EQUAL "1.28.0")
set(SOURCES ${SOURCES} src/MpvPlayerBackend.cpp)
else()
add_definitions(-DDISABLE_MpvPlayerBackend)
endif(MPV_VERSION VERSION_GREATER_EQUAL "1.28.0")
find_program(CCACHE_FOUND ccache)
find_program(CCACHE_FOUND cache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
@ -52,7 +41,7 @@ endif(CCACHE_FOUND)
set(CMAKE_BUILD_TYPE RELEASE)
if(TESTING OR DEFINED ENV{TRAVIS})
if(DEFINED ENV{TRAVIS})
execute_process(
COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
@ -61,37 +50,7 @@ execute_process(
)
find_package(Qt5Network REQUIRED)
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
endif(TESTING OR DEFINED ENV{TRAVIS})
if(TESTING)
SET(CMAKE_C_COMPILER "/usr/bin/clang")
SET(CMAKE_CXX_COMPILER "/usr/bin/clang++")
SET(CMAKE_AR "/usr/bin/llvm-ar")
SET(CMAKE_LINKER "/usr/bin/llvm-link")
SET(CMAKE_NM "/usr/bin/llvm-nm")
SET(CMAKE_OBJDUMP "/usr/bin/llvm-objdump")
SET(CMAKE_RANLIB "/usr/bin/llvm-ranlib")
endif(TESTING)
if(DEVELOP)
set(SOURCES ${SOURCES} runtimeqml/runtimeqml.cpp)
add_definitions(-DQRC_SOURCE_PATH="${PROJECT_SOURCE_DIR}/src/qml")
add_definitions(-DQT_QML_DEBUG)
endif(DEVELOP)
if(DISCORD)
add_definitions(-DDISCORD)
execute_process(
COMMAND git clone --depth 1 https://github.com/discordapp/discord-rpc
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(discord-rpc)
INCLUDE_DIRECTORIES(discord-rpc/include)
target_link_libraries(KittehPlayer discord-rpc)
endif(DISCORD)
endif(DEFINED ENV{TRAVIS})
add_executable(KittehPlayer ${SOURCES} ${qml_QRC})

View file

@ -1,36 +0,0 @@
TARGET = KittehPlayer
TEMPLATE = app
QT += qml quickcontrols2 widgets
SOURCES += src/main.cpp src/MpvPlayerBackend.cpp src/DirectMpvPlayerBackend.cpp src/utils.cpp
CONFIG += debug
CONFIG-=qtquickcompiler
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig
PKGCONFIG += mpv
RESOURCES += src/qml/qml.qrc
unix {
isEmpty {
PREFIX = /usr
}
target.path = $$PREFIX/bin
desktop.files = KittehPlayer.desktop
desktop.path = $$PREFIX/share/applications/
icon.files += KittehPlayer.png
icon.path = $$PREFIX/share/icons/hicolor/256x256/apps/
INSTALLS += desktop
INSTALLS += icon
}
INSTALLS += target
HEADERS += src/MpvPlayerBackend.h src/DirectMpvPlayerBackend.h src/utils.hpp
DISTFILES += KittehPlayer.desktop KittehPlayer.png README.md LICENSE.txt

View file

@ -27,13 +27,12 @@ pacman -S git cmake qt5-svg qt5-declarative qt5-quickcontrols qt5-quickcontrols2
```
sudo add-apt-repository ppa:beineri/opt-qt-5.11.1-xenial -y
sudo apt update
sudo apt install build-essential git nasm qt511-meta-minimal qt511quickcontrols qt511quickcontrols2 qt511imageformats qt511svg libgl1-mesa-dev
sudo apt install build-essential git nasm qt511-meta-minimal qt511quickcontrols qt511quickcontrols2 qt511imageformats qt511svg libgl1-mesa-dev libmpv-dev
sudo apt-get build-dep mpv libmpv* ffmpeg
```
#### Instructions
- `git clone https://github.com/NamedKitten/KittehPlayer KittehPlayer`
- `cd KittehPlayer`
- If you are running Ubuntu you will need to run `sudo ./scripts/build-mpv.sh` because ubuntu's MPV version is way too old.
- `mkdir build && cd build`
- `cmake .. -DCMAKE_INSTALL_PREFIX=/usr`
- `make`
@ -41,4 +40,4 @@ sudo apt-get build-dep mpv libmpv* ffmpeg
- The finished player will then be installed and you can launch it using `KittehPlayer`
## Configuration
- For docs on KittehPlayer please view DOCS.md or `man KittehPlayer`
- For docs on KittehPlayer please view DOCS.md or `man KittehPlayer`

75
runtimeqml/.gitignore vendored
View file

@ -1,75 +0,0 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# qtcreator builds of test project
build-RuntimeQML-*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View file

@ -1,24 +0,0 @@
Copyright (c) 2018, Benjamin Balga
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,87 +0,0 @@
# Runtime QML for Qt
**Written by**: *Benjamin Balga.*
**Copyright**: ***2018***, *Benjamin Balga*, released under BSD license.
## About
This is a base project to get runtime QML reload in your Qt project.
It allows you to reload all QML code at runtime, without recompiling or restarting your app, saving time.
With auto-reload, QML files are watched (based on the QRC file) and reloaded when you save them, or can trigger it manually.
On reload, all windows are closed, and the main window is reloaded. All "QML-only data" is lost, so use links to C++ models/properties as needed.
It only works with Window component as top object, or QQuickWindow subclasses.
### Examples
Example project is located here: https://github.com/GIPdA/runtimeqml_examples
## How to use it in your project
Clone the repo into your project (or copy-paste the ```runtimeqml``` folder) and import the ```.pri``` project file into your ```.pro``` file:
include(runtimeqml/runtimeqml.pri)
### With Qbs
The Qbs project file includes RuntimeQML as a static library. Check the example project to see how to include it in your project.
## Usage
Include ```runtimeqml.h``` header file, and create the RuntimeQML object (after the QML engine) :
RuntimeQML *rt = new RuntimeQML(&engine, QRC_SOURCE_PATH"/qml.qrc");
The second argument is the path to your qrc file listing all your QML files, needed for the auto-reload feature only. You can omit it if you don't want auto-reload.
```QRC_SOURCE_PATH``` is defined in the ```.pri/.qbs``` file to its parent path, just to not have to manually set an absolute path...
Set the "options" you want, or not:
rt->noDebug(); // Removes debug prints
rt->setAutoReload(true); // Enable auto-reload (begin to watch files)
//rt->setCloseAllOnReload(false); // Don't close all windows on reload. Not advised!
rt->setMainQmlFilename("main.qml"); // This is the file that loaded on reload, default is "main.qml"
For the auto-reload feature:
rt->addSuffix("conf"); // Adds a file suffix to the "white list" for watched files. "qml" is already in.
rt->ignorePrefix("/test"); // Ignore a prefix in the QRC file.
rt->ignoreFile("/Page2.qml"); // Ignore a file name with prefix (supports classic wildcard matching)
Then load the main QML file :
rt->reload();
And you're all set!
You can also check the test project. Beware, includes and defines differs a bit...
## Manual reload
Add the RuntimeQML object to the QML context:
engine.rootContext()->setContextProperty("RuntimeQML", rt);
Trigger the reload when and where you want, like with a button:
Button {
text: "Reload"
onClicked: {
RuntimeQML.reload();
}
}
You can do it in C++ too, of course.
## License
See LICENSE file.

View file

@ -1,398 +0,0 @@
#include "runtimeqml.h"
#include <QXmlStreamReader>
#include <QFileInfo>
#include <QRegExp>
#include <QTimer>
/*!
* \brief Construct a RuntimeQML object with a path to the qrc file.
* \param engine App engine to reload.
* \param qrcFilename File name of the QRC file for auto reload.
* \param parent Pointer to a parent object.
*/
RuntimeQML::RuntimeQML(QQmlApplicationEngine* engine, const QString &qrcFilename, QObject *parent) :
QObject(parent),
m_engine(engine),
m_qrcFilename(qrcFilename),
m_mainQmlFilename("main.qml")
{
m_allowedSuffixList << "qml";
}
/*!
* \brief Returns the absolute path for the given qml file.
* \param qmlFile Qml filename
*/
QString RuntimeQML::adjustPath(QString qmlFile)
{
return m_selector.select(qrcAbsolutePath() + "/" + qmlFile);
}
/*!
* \brief Returns the absolute path to the QRC file.
*/
QString RuntimeQML::qrcAbsolutePath() const
{
return QFileInfo(m_qrcFilename).absolutePath();
}
/*!
* \brief Filename of the QRC file.
*/
QString RuntimeQML::qrcFilename() const
{
return m_qrcFilename;
}
/*!
* \brief If true, files are watched for changes and auto-reloaded.
* Otherwise, you need to trigger a reload manually from your code by calling reload().
* \sa reload
*/
bool RuntimeQML::autoReload() const
{
return m_autoReload;
}
/*!
* \brief If true, all open windows will be closed upon reload.
* \default true
*/
bool RuntimeQML::closeAllOnReload() const
{
return m_closeAllOnReload;
}
/*!
* \brief QRC prefixes that are ignored.
*/
const QList<QString>& RuntimeQML::prefixIgnoreList() const
{
return m_prefixIgnoreList;
}
/*!
* \brief Files that are ignored.
*/
const QList<QString> &RuntimeQML::fileIgnoreList() const
{
return m_fileIgnoreList;
}
/*!
* \brief Allowed suffixes to filter files to watch for changes.
* By default contains only "qml".
*/
const QList<QString> &RuntimeQML::allowedSuffixes() const
{
return m_allowedSuffixList;
}
/*!
* \brief Call it if you don't want debug outputs from this class.
*/
void RuntimeQML::noDebug()
{
if (m_noDebug)
return;
m_noDebug = true;
}
/*!
* \brief Reload the window.
*/
void RuntimeQML::reload()
{
QMetaObject::invokeMethod(this, "reloadQml", Qt::QueuedConnection);
}
/*!
* \brief Call it from QML to set the current QQuickWindow.
* You shouldn't need to call it as it is done automatically on reload.
* \param window
*/
void RuntimeQML::setWindow(QQuickWindow* window)
{
if (window == m_window)
return;
m_window = window;
}
/*!
* \brief Set the QRC filename for files to watch for changes.
* \param qrcFilename Path to a .qrc file.
*/
void RuntimeQML::setQrcFilename(QString qrcFilename)
{
if (m_qrcFilename == qrcFilename)
return;
m_qrcFilename = qrcFilename;
emit qrcFilenameChanged(qrcFilename);
loadQrcFiles();
}
/*!
* \brief Set the name of the main qml file.
* Default is "main.qml".
* \param filename The main qml filename.
*/
void RuntimeQML::setMainQmlFilename(QString filename)
{
if (m_mainQmlFilename == filename)
return;
m_mainQmlFilename = filename;
}
/*!
* \brief If true, files are watched for changes and auto-reloaded.
* Otherwise, you need to trigger a reload manually from your code by calling reload().
* \param reload True to auto-reload, false otherwise.
*/
void RuntimeQML::setAutoReload(bool autoReload)
{
if (m_autoReload == autoReload)
return;
m_autoReload = autoReload;
emit autoReloadChanged(autoReload);
if (autoReload)
loadQrcFiles();
else
unloadFileWatcher();
}
/*!
* \brief If true, all open windows are closed upon reload. Otherwise, might cause "link" errors with QML components.
* \param closeAllOnReload True to close all windows on reload, false otherwise.
*/
void RuntimeQML::setCloseAllOnReload(bool closeAllOnReload)
{
if (m_closeAllOnReload == closeAllOnReload)
return;
m_closeAllOnReload = closeAllOnReload;
emit closeAllOnReloadChanged(m_closeAllOnReload);
}
/*!
* \brief Add a QRC prefix to ignore.
* \note Relevant for auto-reload only.
* \param prefix Prefix to ignore.
*/
void RuntimeQML::ignoreQrcPrefix(const QString& prefix)
{
if (m_prefixIgnoreList.contains(prefix))
return;
m_prefixIgnoreList.append(prefix);
if (m_autoReload)
loadQrcFiles();
}
/*!
* \brief Add a filename to ignore from changes.
* Applies to the full filename in the QRC entry (i.e. the local "path"), with the prefix.
* Supports "file globbing" matching using wildcards.
* \note Relevant for auto-reload only.
* \param filename Filename to ignore.
*/
void RuntimeQML::ignoreFile(const QString &filename)
{
if (m_fileIgnoreList.contains(filename))
return;
m_fileIgnoreList.append(filename);
if (m_autoReload)
loadQrcFiles();
}
/*!
* \brief Allow a file suffix to be watched for changes.
* \note Relevant for auto-reload only.
* \param suffix
*/
void RuntimeQML::addSuffix(const QString &suffix)
{
if (m_allowedSuffixList.contains(suffix))
return;
m_allowedSuffixList.append(suffix);
if (m_autoReload)
loadQrcFiles();
}
/*!
* \brief Reload the QML. Do not call it directly, use reload() instead.
*/
void RuntimeQML::reloadQml()
{
if (m_mainQmlFilename.isEmpty()) {
qWarning("No QML file specified.");
return;
}
if (m_window) {
if (m_closeAllOnReload) {
// Find all child windows and close them
auto const allWindows = m_window->findChildren<QQuickWindow*>();
for (int i {0}; i < allWindows.size(); ++i) {
QQuickWindow* w = qobject_cast<QQuickWindow*>(allWindows.at(i));
if (w) {
w->close();
w->deleteLater();
}
}
}
m_window->close();
m_window->deleteLater();
}
m_engine->clearComponentCache();
// TODO: test with network files
// TODO: QString path to QUrl doesn't work under Windows with load() (load fail)
m_engine->load(m_selector.select(qrcAbsolutePath() + "/" + m_mainQmlFilename));
// NOTE: QQmlApplicationEngine::rootObjects() isn't cleared, should it be?
if (!m_engine->rootObjects().isEmpty()) {
QQuickWindow* w = qobject_cast<QQuickWindow*>(m_engine->rootObjects().last());
if (w) m_window = w;
}
// for (auto *o : m_engine->rootObjects()) {
// qDebug() << "> " << o;
// }
}
/*!
* \brief Called when a watched file changed, from QFileSystemWatcher.
* \param path Path/file that triggered the signal.
*/
void RuntimeQML::fileChanged(const QString& path)
{
if (!m_noDebug)
qDebug() << "Reloading qml:" << path;
reload();
#if defined(Q_OS_WIN)
// Deleted files are removed from the watcher, re-add the file for
// systems that delete files to update them
if (m_fileWatcher)
QTimer::singleShot(500, m_fileWatcher, [this,path](){
m_fileWatcher->addPath(path);
});
#endif
}
/*!
* \brief Load qml from the QRC file to watch them.
*/
void RuntimeQML::loadQrcFiles()
{
unloadFileWatcher();
m_fileWatcher = new QFileSystemWatcher(this);
connect(m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &RuntimeQML::fileChanged);
QFile file(m_qrcFilename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning("Unable to open resource file '%s', RuntimeQML will not work! Error: %s",
qPrintable(m_qrcFilename), qPrintable(file.errorString()));
return;
}
QString const basePath = qrcAbsolutePath() + "/";
QString currentPrefix;
// Read each entry
QXmlStreamReader inputStream(&file);
while (!inputStream.atEnd() && !inputStream.hasError()) {
inputStream.readNext();
if (inputStream.isStartElement()) {
QString name { inputStream.name().toString() };
// Check prefix
if (name == "qresource") {
if (inputStream.attributes().hasAttribute("prefix")) {
auto p = inputStream.attributes().value("prefix").toString();
if (m_prefixIgnoreList.contains(p)) {
// Ignore this prefix, loop through elements in this 'qresource' tag
while (!inputStream.atEnd() && !inputStream.hasError()) {
inputStream.readNext();
if (inputStream.isEndElement() && inputStream.name() == "qresource")
break;
}
continue;
}
currentPrefix = p;
}
}
// Check file name
if (name == "file") {
QString const filename { inputStream.readElementText() };
// Check ignore list
QString const fullFilename { currentPrefix + filename };
auto it = std::find_if(m_fileIgnoreList.cbegin(), m_fileIgnoreList.cend(), [&](QString const& pattern) {
QRegExp re(pattern);
re.setPatternSyntax(QRegExp::WildcardUnix);
return re.exactMatch(fullFilename);
});
if (it != m_fileIgnoreList.cend())
continue;
QFileInfo const file { filename };
// Add to the watch list if the file suffix is allowed
if (m_allowedSuffixList.contains(file.suffix())) {
QString fp { m_selector.select(basePath + filename) };
m_fileWatcher->addPath(fp);
//qDebug() << " " << file.absoluteFilePath() << fp;
}
}
}
}
if (!m_noDebug) {
qDebug("Watching QML files:");
int const fileCount = m_fileWatcher->files().size();
for (auto &f : m_fileWatcher->files()) {
qDebug() << " " << f;
}
if (fileCount > 0)
qDebug(" Total: %d", fileCount);
else
qDebug(" None.");
}
}
/*!
* \brief Unload the file watcher.
*/
void RuntimeQML::unloadFileWatcher()
{
if (m_fileWatcher) {
disconnect(m_fileWatcher);
delete m_fileWatcher;
m_fileWatcher = nullptr;
}
}

View file

@ -1,82 +0,0 @@
#ifndef RUNTIMEQML_H
#define RUNTIMEQML_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QFileSelector>
#include <QFileSystemWatcher>
#include <QDebug>
class RuntimeQML : public QObject
{
Q_OBJECT
Q_PROPERTY(QString qrcFilename READ qrcFilename WRITE setQrcFilename NOTIFY qrcFilenameChanged)
Q_PROPERTY(bool autoReload READ autoReload WRITE setAutoReload NOTIFY autoReloadChanged)
Q_PROPERTY(bool closeAllOnReload READ closeAllOnReload WRITE setCloseAllOnReload NOTIFY closeAllOnReloadChanged)
public:
explicit RuntimeQML(QQmlApplicationEngine *engine, QString const& qrcFilename = QString(), QObject *parent = 0);
// If using QQmlFileSelector with Loader
Q_INVOKABLE QString adjustPath(QString qmlFile);
Q_INVOKABLE QString qrcAbsolutePath() const;
QString qrcFilename() const;
bool autoReload() const;
bool closeAllOnReload() const;
QList<QString> const & prefixIgnoreList() const;
QList<QString> const & fileIgnoreList() const;
QList<QString> const & allowedSuffixes() const;
void noDebug();
signals:
void autoReloadChanged(bool autoReload);
void qrcFilenameChanged(QString qrcFilename);
void closeAllOnReloadChanged(bool closeAllOnReload);
public slots:
void reload();
void setWindow(QQuickWindow* window);
void setQrcFilename(QString qrcFilename);
void setMainQmlFilename(QString filename);
void setAutoReload(bool autoReload);
void setCloseAllOnReload(bool closeAllOnReload);
void ignoreQrcPrefix(QString const& prefix);
void ignoreFile(QString const& filename);
void addSuffix(QString const& suffix);
private slots:
void reloadQml();
void fileChanged(const QString &path);
private:
void loadQrcFiles();
void unloadFileWatcher();
QQmlApplicationEngine *m_engine {nullptr};
QQuickWindow *m_window {nullptr};
QFileSelector m_selector;
QString m_qrcFilename;
QString m_mainQmlFilename;
bool m_autoReload {false};
QFileSystemWatcher* m_fileWatcher {nullptr};
QList<QString> m_prefixIgnoreList;
QList<QString> m_fileIgnoreList;
QList<QString> m_allowedSuffixList;
bool m_noDebug {false};
bool m_closeAllOnReload {true};
};
#endif // RUNTIMEQML_H

View file

@ -1,13 +0,0 @@
# Qt Quick Runtime Reloader
QT += core qml quick
INCLUDEPATH += $$PWD
DEFINES += "QRC_SOURCE_PATH=\\\"$$PWD/..\\\""
SOURCES += \
$$PWD/runtimeqml.cpp
HEADERS += \
$$PWD/runtimeqml.h

View file

@ -1,18 +0,0 @@
import qbs 1.0
StaticLibrary {
name: "runtimeqml"
files: [
"runtimeqml.cpp",
"runtimeqml.h",
]
Depends { name: 'cpp' }
Depends { name: "Qt.core" }
Depends { name: "Qt.quick" }
Export {
Depends { name: "cpp" }
cpp.includePaths: [product.sourceDirectory]
cpp.defines: ['QRC_SOURCE_PATH="'+path+'/.."']
}
}

View file

@ -14,10 +14,6 @@
#include <QSequentialIterable>
#include <math.h>
#ifdef DISCORD
#include "discord_rpc.h"
#endif
void
wakeup(void* ctx)
{
@ -79,12 +75,6 @@ DirectMpvPlayerBackend::DirectMpvPlayerBackend(QQuickItem* parent)
if (!mpv)
throw std::runtime_error("could not create mpv context");
#ifdef DISCORD
DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers));
Discord_Initialize("511220330996432896", &handlers, 1, NULL);
#endif
mpv_set_option_string(mpv, "terminal", "yes");
mpv_set_option_string(mpv, "msg-level", "all=v");
@ -234,25 +224,6 @@ DirectMpvPlayerBackend::launchAboutQt()
qapp->aboutQt();
}
#ifdef DISCORD
void
DirectMpvPlayerBackend::updateDiscord()
{
char buffer[256];
DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
sprintf(buffer,
"Currently Playing: Video %s",
getProperty("media-title").toString().toUtf8().constData());
discordPresence.details = buffer;
discordPresence.startTimestamp = time(0);
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
getProperty("time-pos").toFloat());
discordPresence.instance = 0;
Discord_UpdatePresence(&discordPresence);
}
#endif
QVariant
DirectMpvPlayerBackend::playerCommand(const Enums::Commands& cmd)
{
@ -606,9 +577,6 @@ DirectMpvPlayerBackend::handle_mpv_event(mpv_event* event)
double speed = *(double*)prop->data;
emit speedChanged(speed);
}
#ifdef DISCORD
updateDiscord();
#endif
break;
}
case MPV_EVENT_SHUTDOWN: {

View file

@ -103,9 +103,6 @@ private slots:
private:
void handle_mpv_event(mpv_event* event);
#ifdef DISCORD
void updateDiscord();
#endif
};
#endif

View file

@ -12,10 +12,6 @@
#include <QSequentialIterable>
#include <math.h>
#ifdef DISCORD
#include "discord_rpc.h"
#endif
#ifdef __linux__
#include <QX11Info>
#include <QtX11Extras/QX11Info>
@ -136,12 +132,6 @@ MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
if (!mpv)
throw std::runtime_error("could not create mpv context");
#ifdef DISCORD
DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers));
Discord_Initialize("511220330996432896", &handlers, 1, NULL);
#endif
mpv_set_option_string(mpv, "terminal", "yes");
mpv_set_option_string(mpv, "msg-level", "all=v");
@ -243,33 +233,6 @@ MpvPlayerBackend::setOption(const QString& name, const QVariant& value)
mpv::qt::set_option_variant(mpv, name, value);
}
void
MpvPlayerBackend::launchAboutQt()
{
QApplication* qapp =
qobject_cast<QApplication*>(QCoreApplication::instance());
qapp->aboutQt();
}
#ifdef DISCORD
void
MpvPlayerBackend::updateDiscord()
{
char buffer[256];
DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
sprintf(buffer,
"Currently Playing: Video %s",
getProperty("media-title").toString().toUtf8().constData());
discordPresence.details = buffer;
discordPresence.startTimestamp = time(0);
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
getProperty("time-pos").toFloat());
discordPresence.instance = 0;
Discord_UpdatePresence(&discordPresence);
}
#endif
QVariant
MpvPlayerBackend::playerCommand(const Enums::Commands& cmd)
{
@ -496,12 +459,6 @@ MpvPlayerBackend::updateDurationString(int numTime)
emit durationStringChanged(durationString);
}
void
MpvPlayerBackend::updateAppImage()
{
Utils::updateAppImage();
}
QVariantMap
MpvPlayerBackend::getAudioDevices(const QVariant& drivers) const
{
@ -591,9 +548,6 @@ MpvPlayerBackend::handle_mpv_event(mpv_event* event)
double speed = *(double*)prop->data;
emit speedChanged(speed);
}
#ifdef DISCORD
updateDiscord();
#endif
break;
}
case MPV_EVENT_SHUTDOWN: {

View file

@ -46,9 +46,7 @@ public:
public slots:
QVariant playerCommand(const Enums::Commands& command, const QVariant& args);
QVariant playerCommand(const Enums::Commands& command);
void launchAboutQt();
void toggleOnTop();
void updateAppImage();
// Optional but handy for MPV or custom backend settings.
void command(const QVariant& params);
void setProperty(const QString& name, const QVariant& value);
@ -87,9 +85,6 @@ private slots:
private:
void handle_mpv_event(mpv_event* event);
#ifdef DISCORD
void updateDiscord();
#endif
};
#endif

View file

@ -17,9 +17,7 @@ public slots:
virtual QVariant playerCommand(const Enums::Commands& command,
const QVariant& args) = 0;
virtual QVariant playerCommand(const Enums::Commands& command) = 0;
virtual void launchAboutQt() = 0;
virtual void toggleOnTop() = 0;
virtual void updateAppImage() = 0;
// Optional but handy for MPV or custom backend settings.
virtual void command(const QVariant& params) = 0;
virtual void setProperty(const QString& name, const QVariant& value) = 0;

View file

@ -1,7 +1,3 @@
#ifdef QRC_SOURCE_PATH
#include "runtimeqml/runtimeqml.h"
#endif
#include "DirectMpvPlayerBackend.h"
#ifndef DISABLE_MpvPlayerBackend
#include "MpvPlayerBackend.h"
@ -138,7 +134,6 @@ main(int argc, char* argv[])
qRegisterMetaType<Enums::PlayStatus>("Enums.PlayStatus");
qRegisterMetaType<Enums::VolumeStatus>("Enums.VolumeStatus");
qRegisterMetaType<Enums::Backends>("Enums.Backends");
qRegisterMetaType<Enums::Commands>("Enums.Commands");
qmlRegisterType<UtilsClass>("player", 1, 0, "Utils");
@ -164,15 +159,7 @@ main(int argc, char* argv[])
std::setlocale(LC_NUMERIC, "C");
QQmlApplicationEngine engine;
#ifdef QRC_SOURCE_PATH
RuntimeQML* rt = new RuntimeQML(&engine, QRC_SOURCE_PATH "/qml.qrc");
rt->setAutoReload(true);
rt->setMainQmlFilename("main.qml");
rt->reload();
#else
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
#endif
return app.exec();
}

View file

@ -123,7 +123,7 @@ Item {
Item {
id: controlsBar
height: controlsBar.visible ? mainWindow.virtualHeight / 24 : 0
height: controlsBar.visible ? mainWindow.virtualHeight / 20 : 0
anchors.right: parent.right
anchors.rightMargin: parent.width / 128
anchors.left: parent.left

View file

@ -218,7 +218,7 @@ MenuBar {
}
Action {
text: translate.getTranslation("UPDATE", i18n.language)
onTriggered: player.updateAppImage()
onTriggered: utils.updateAppImage()
}
}
@ -520,7 +520,7 @@ MenuBar {
Action {
text: translate.getTranslation("ABOUT_QT", i18n.language)
onTriggered: {
player.launchAboutQt()
utils.launchAboutQt()
}
}
}

View file

@ -18,8 +18,7 @@ Button {
appearance.themeName, "buttonColor")
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
display: AbstractButton.IconOnly
onClicked: {
var aptn = appearance.themeName
appearance.themeName = aptn == "YouTube" ? "RoosterTeeth" : aptn

View file

@ -22,20 +22,20 @@ Button {
}
background: Item {
}
function updateStatus(status) {
if (volumeButton == null)
console.log("OwO")
if (status == Enums.VolumeStatus.Muted) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-mute.svg"
} else if (status == Enums.VolumeStatus.Low) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-down.svg"
} else if (status == Enums.VolumeStatus.Normal) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-up.svg"
}
function updateStatus(status) {
if (volumeButton == null)
console.log("OwO")
if (status == Enums.VolumeStatus.Muted) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-mute.svg"
} else if (status == Enums.VolumeStatus.Low) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-down.svg"
} else if (status == Enums.VolumeStatus.Normal) {
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-up.svg"
}
}
Connections {
target: player
enabled: true

View file

@ -45,7 +45,7 @@ Slider {
x: volumeBar.leftPadding
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
implicitWidth: layout.width / 11
implicitHeight: appearance.themeName == "Niconico" ? layout.height / 8 : layout.height / 10
implicitHeight: appearance.themeName == "Niconico" ? layout.height / 6 : layout.height / 10
width: volumeBar.availableWidth
height: implicitHeight
color: getAppearanceValueForTheme(appearance.themeName,

View file

@ -45,13 +45,12 @@ Item {
anchors.left: volumeButton.left
anchors.right: volumeSlider.right
anchors.top: parent.top
width: volumeButton.width
+ (volumeSlider.visible ? volumeSlider.width : 0)
width: volumeButton.width + (volumeSlider.visible ? volumeSlider.width : 0)
hoverEnabled: true
propagateComposedEvents: true
acceptedButtons: Qt.NoButton
}
VolumeButton {
id: volumeButton
anchors.left: playlistNextButton.right

View file

@ -25,6 +25,15 @@ getPlatformName()
qobject_cast<QGuiApplication*>(QCoreApplication::instance());
return qapp->platformName();
}
void
launchAboutQt()
{
QApplication* qapp =
qobject_cast<QApplication*>(QCoreApplication::instance());
qapp->aboutQt();
}
void
updateAppImage()
{

View file

@ -15,8 +15,12 @@ void
AlwaysOnTop(WId wid, bool on);
void
updateAppImage();
int
fast_mod(const int input, const int ceil);
QString
createTimestamp(int seconds);
void
launchAboutQt();
}
class UtilsClass : public QObject
@ -26,6 +30,8 @@ public slots:
void SetDPMS(bool on) { Utils::SetDPMS(on); };
void AlwaysOnTop(WId wid, bool on) { Utils::AlwaysOnTop(wid, on); };
void updateAppImage() { Utils::updateAppImage(); };
void launchAboutQt() { Utils::launchAboutQt(); };
QString createTimestamp(int seconds)
{
return Utils::createTimestamp(seconds);