# qtcreator generated files
*.pro.user
*.pro.user.*
+CMakeLists.txt.user
*.autosave
*.files
*.creator
# ---------------------
build
+cmakebuild
debug
release
lib/qtsingleapplication/lib
.tmp
qtc-gdbmacros
test-data
-
-# Binaries
-# --------
-build/*.dll
-build/*.lib
-build/*.exe
-build/*.so*
-
-
--- /dev/null
+cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
+include(FeatureSummary)
+
+project(AniPlayer)
+
+set(QT_MIN_VERSION "5.3.0")
+
+option(WITH_DESKTOP_UI "Build default QML desktop UI" ON)
+add_feature_info(QmlDesktopUI WITH_DESKTOP_UI "default desktop UI, using QML")
+
+option(WITH_BACKEND_MPV "Build MPV backend" ON)
+add_feature_info(BackendMpv WITH_BACKEND_MPV "the MPV backend")
+
+option(WITH_LOCALMYLIST "Build LocalMyList feature plugin" ON)
+add_feature_info(FeatureLocalMyList WITH_LOCALMYLIST "automatically mark files as watched that are in your LocalMyList")
+
+
+add_subdirectory(pluginapi)
+add_subdirectory(core)
+add_subdirectory(backendplugins)
+add_subdirectory(uiplugins)
+add_subdirectory(featureplugins)
+
+feature_summary(WHAT ALL)
--- /dev/null
+project(backendplugins)
+
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/backendplugins)
+
+if (WITH_BACKEND_MPV)
+ add_subdirectory(backend_mpv)
+endif()
--- /dev/null
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+project(backend_mpv)
+
+find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+ Core
+ Gui
+ Qml
+ Quick
+)
+
+set(backend_mpv_LIBS
+ Qt5::Core
+ Qt5::Gui
+ pluginapi
+ # TODO find_package this
+ mpv-1
+)
+
+set(backend_mpv_SOURCES
+ backendmpv.cpp
+)
+
+set(backend_mpv_HEADERS
+ backendmpv.h
+ backend_mpv_global.h
+)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_library(backend_mpv MODULE
+ ${backend_mpv_SOURCES}
+ ${backend_mpv_HEADERS}
+)
+
+set_property(TARGET backend_mpv PROPERTY CXX_STANDARD 14)
+set_property(TARGET backend_mpv PROPERTY OUTPUT_NAME "backend_mpv")
+target_link_libraries(backend_mpv ${backend_mpv_LIBS})
+
+add_definitions(-DBACKEND_MPV_LIBRARY)
+
+if(WIN32)
+ set(INSTALL_DESTINATION "aniplayer/uiplugins")
+else()
+ set(INSTALL_DESTINATION "lib${LIB_SUFFIX}/aniplayer/uiplugins")
+endif()
+
+install(TARGETS backend_mpv
+ LIBRARY DESTINATION ${INSTALL_DESTINATION}
+ ARCHIVE DESTINATION ${INSTALL_DESTINATION}
+)
+install(FILES $<TARGET_PDB_FILE:backend_mpv>
+ DESTINATION ${INSTALL_DESTINATION} OPTIONAL
+)
--- /dev/null
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+project(core)
+
+set(core_VERSION "0.4.0")
+
+add_subdirectory("qtsingleapplication")
+
+find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+ Core
+ Gui
+ Widgets
+ Qml
+ Quick
+)
+
+find_package(LocalMyList CONFIG REQUIRED)
+
+set(core_LIBS
+ Qt5::Core
+ Qt5::Gui
+ Qt5::Widgets
+ Qt5::Qml
+ Qt5::Quick
+ pluginapi
+ qtsingleapplication
+)
+
+if(WITH_ANIDBUDPCLIENT)
+ find_package(AniDBUdpClient CONFIG REQUIRED)
+endif()
+
+set(core_SOURCES
+ main.cpp
+ player.cpp
+ pluginmanager.cpp
+ videoelement.cpp
+ instancemanager.cpp
+ settings.cpp
+ trackmodel.cpp
+ chaptermodel.cpp
+ annotationmodel.cpp
+)
+
+set(core_HEADERS
+ player.h
+ pluginmanager.h
+ videoelement.h
+ instancemanager.h
+ settings.h
+ trackmodel.h
+ chaptermodel.h
+ annotationmodel.h
+)
+
+set(core_PUBLIC_HEADERS
+ include/aniplayer/backendpluginbase.h
+ include/aniplayer/playerplugininterface.h
+ include/aniplayer/featurepluginbase.h
+ include/aniplayer/uipluginbase.h
+ include/aniplayer/playerfeatureplugininterface.h
+)
+
+if(WIN32)
+ set(core_SOURCES
+ ${core_SOURCES}
+ aniplayer.rc
+ )
+ # TODO CMake should handle this automatically
+ set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST:NO")
+endif()
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_executable(core WIN32
+ ${core_SOURCES}
+ ${core_HEADERS}
+)
+
+set_property(TARGET core PROPERTY CXX_STANDARD 14)
+set_property(TARGET core PROPERTY OUTPUT_NAME "aniplayer")
+target_link_libraries(core ${core_LIBS})
+
+install(TARGETS core
+ LIBRARY DESTINATION lib${LIB_SUFFIX}
+ ARCHIVE DESTINATION lib${LIB_SUFFIX}
+ RUNTIME DESTINATION bin
+)
+install(FILES $<TARGET_PDB_FILE:core> DESTINATION bin OPTIONAL)
--- /dev/null
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+project(qtsingleapplication)
+
+find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+ Core
+ Widgets
+ Network
+)
+
+set(qtsingleapplication_LIBS
+ Qt5::Core
+ Qt5::Widgets
+ Qt5::Network
+)
+
+set(qtsingleapplication_SOURCES
+ qtsingleapplication.cpp
+ qtlocalpeer.cpp
+)
+
+set(qtsingleapplication_HEADERS
+ qtsingleapplication.h
+ qtlocalpeer.h
+)
+
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_library(qtsingleapplication STATIC
+ ${qtsingleapplication_SOURCES}
+ ${qtsingleapplication_HEADERS}
+)
+
+set_property(TARGET qtsingleapplication PROPERTY CXX_STANDARD 14)
+target_link_libraries(qtsingleapplication ${qtsingleapplication_LIBS})
+if(WIN32)
+ add_definitions(-DUNICODE -D_UNICODE)
+endif()
+
--- /dev/null
+project(featureplugins)
+
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/featureplugins)
+
+if (WITH_LOCALMYLIST)
+ add_subdirectory(feature_localmylist)
+endif()
--- /dev/null
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+project(feature_localmylist)
+
+find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+ Core
+)
+
+find_package(LocalMyList CONFIG REQUIRED)
+
+set(feature_localmylist_LIBS
+ Qt5::Core
+ pluginapi
+ # TODO find_package this
+ LocalMyList::LocalMyList
+)
+
+set(feature_localmylist_SOURCES
+ featurelocalmylist.cpp
+)
+
+set(feature_localmylist_HEADERS
+ featurelocalmylist.h
+ feature_localmylist_global.h
+)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_library(feature_localmylist MODULE
+ ${feature_localmylist_SOURCES}
+ ${feature_localmylist_HEADERS}
+)
+
+set_property(TARGET feature_localmylist PROPERTY CXX_STANDARD 14)
+set_property(TARGET feature_localmylist PROPERTY OUTPUT_NAME "feature_localmylist")
+target_link_libraries(feature_localmylist ${feature_localmylist_LIBS})
+
+add_definitions(-DFEATURE_LOCALMYLIST_LIBRARY)
+
+if(WIN32)
+ set(INSTALL_DESTINATION "aniplayer/uiplugins")
+else()
+ set(INSTALL_DESTINATION "lib${LIB_SUFFIX}/aniplayer/uiplugins")
+endif()
+
+install(TARGETS feature_localmylist
+ LIBRARY DESTINATION ${INSTALL_DESTINATION}
+ ARCHIVE DESTINATION ${INSTALL_DESTINATION}
+)
+install(FILES $<TARGET_PDB_FILE:feature_localmylist>
+ DESTINATION ${INSTALL_DESTINATION} OPTIONAL
+)
--- /dev/null
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+project(pluginapi CXX)
+
+set(pluginapi_PUBLIC_HEADERS
+ aniplayer/backendpluginbase.h
+ aniplayer/playerplugininterface.h
+ aniplayer/featurepluginbase.h
+ aniplayer/uipluginbase.h
+ aniplayer/playerfeatureplugininterface.h
+)
+
+add_library(pluginapi INTERFACE)
+find_package(Qt5 COMPONENTS Core)
+target_link_libraries(pluginapi INTERFACE ${pluginapi_LIBS})
+target_link_libraries(pluginapi INTERFACE Qt5::Core)
+
+install(FILES ${pluginapi_PUBLIC_HEADERS}
+ DESTINATION include/aniplayer
+)
+
+# IDE hack
+#project(pluginapi_ide CXX)
+add_custom_target(pluginapi_ide SOURCES ${pluginapi_PUBLIC_HEADERS})
+
--- /dev/null
+#ifndef BACKENDPLUGINBASE_H
+#define BACKENDPLUGINBASE_H
+
+#include "playerplugininterface.h"
+
+class QUrl;
+
+class BackendInstance {
+public:
+ using TrackIndex = int;
+ // In seconds
+ using TimeStamp = double;
+ // Volume valid range is 0.0-1.0
+ using Volume = double;
+ virtual ~BackendInstance() = default;
+
+ virtual VideoRendererBase *createRenderer(VideoUpdateInterface *) = 0;
+
+ virtual bool open(const QUrl &resource) = 0;
+
+ virtual void play() = 0;
+ virtual void pause() = 0;
+ virtual void stop() = 0;
+
+ virtual void seek(TimeStamp) = 0;
+
+ virtual void setVolume(Volume) = 0;
+
+ virtual void setCurrentVideoStream(TrackIndex) = 0;
+ virtual void setCurrentAudioStream(TrackIndex) = 0;
+ virtual void setCurrentSubtitleStream(TrackIndex) = 0;
+};
+
+class BackendPluginBase {
+public:
+ virtual ~BackendPluginBase() = default;
+
+ virtual BackendInstance *createInstance(PlayerPluginInterface *) = 0;
+};
+
+#define ANIPLAYER_BACKEND_DPLUGIN_INTERFACE_IID \
+ "org.aptx.aniplayer.BackendPluginInterface"
+
+#include <QObject>
+Q_DECLARE_INTERFACE(BackendPluginBase, ANIPLAYER_BACKEND_DPLUGIN_INTERFACE_IID)
+
+#endif // BACKENDPLUGINBASE_H
--- /dev/null
+#ifndef FEATUREPLUGINBASE_H
+#define FEATUREPLUGINBASE_H
+
+#include <QObject>
+
+#include "aniplayer/playerfeatureplugininterface.h"
+
+class FeaturePluginInstance {
+public:
+ virtual ~FeaturePluginInstance() = default;
+
+ FeaturePluginInstance(QObject *player,
+ PlayerFeaturePlauginInterface *interface)
+ : m_player{player}, m_playerInterface{interface} {}
+
+protected:
+ QObject *m_player;
+ PlayerFeaturePlauginInterface *m_playerInterface;
+};
+
+class FeaturePluginBase {
+public:
+ virtual ~FeaturePluginBase() = default;
+
+ virtual FeaturePluginInstance *
+ createInstance(QObject *instance, PlayerFeaturePlauginInterface *) = 0;
+};
+
+#define ANIPLAYER_FEATURE_PLUGIN_INTERFACE_IID \
+ "org.aptx.aniplayer.FeaturePluginInterface"
+
+Q_DECLARE_INTERFACE(FeaturePluginBase, ANIPLAYER_FEATURE_PLUGIN_INTERFACE_IID)
+
+#endif // FEATUREPLUGINBASE_H
--- /dev/null
+#ifndef PLAYERFEATUREPLUGININTERFACE_H
+#define PLAYERFEATUREPLUGININTERFACE_H
+
+#include <QString>
+#include <QList>
+
+class PlayerFeaturePlauginInterface {
+public:
+ struct Annotation {
+ double x;
+ double y;
+ double w;
+ double h;
+ QString color;
+ QString text;
+ };
+
+ using AnnotationList = QList<Annotation>;
+
+ virtual ~PlayerFeaturePlauginInterface() = default;
+
+ virtual void featureShowStatusMessage(const QString &message) = 0;
+
+ virtual void featureSetAnnotations(const AnnotationList &) = 0;
+};
+
+#endif // PLAYERFEATUREPLUGININTERFACE_H
--- /dev/null
+#ifndef PLAYERPLUGININTERFACE_H
+#define PLAYERPLUGININTERFACE_H
+
+#include <QtGlobal>
+#include <QUrl>
+
+class QOpenGLFramebufferObject;
+
+class VideoUpdateInterface {
+public:
+ virtual ~VideoUpdateInterface() = default;
+
+ virtual void videoUpdated() = 0;
+};
+
+class PlayerPluginInterface {
+public:
+ using TrackIndex = int;
+ using TimeStamp = double;
+ using Volume = double;
+
+ enum class PlayState { Stopped, Paused, Playing };
+ /*
+ * .-----.
+ * | | Error
+ * v |
+ * Stopped -'<--+<-------.
+ * | ^ |
+ * | Load | Error |
+ * v | |
+ * Paused<------+ | File End
+ * | ^ |
+ * | Play | Pause |
+ * v | |
+ * Playing------+--------'
+ */
+
+ virtual ~PlayerPluginInterface() = default;
+
+ virtual void backendReadyToPlay() = 0;
+
+ virtual void backendSourceChanged(QUrl source) = 0;
+ virtual void playStateChanged(PlayState) = 0;
+ virtual void playbackDurationChanged(TimeStamp) = 0;
+ virtual void playbackPositionChanged(TimeStamp) = 0;
+ virtual void playbackVolumeChanged(Volume) = 0;
+ virtual void playbackMaxVolumeChanged(Volume) = 0;
+
+ struct Track {
+ QString title;
+ QString language;
+ int id;
+ };
+ using TrackList = QList<Track>;
+ virtual void backendVideoTracksChanged(const TrackList &) = 0;
+ virtual void backendAudioTracksChanged(const TrackList &) = 0;
+ virtual void backendSubtitleTracksChanged(const TrackList &) = 0;
+
+ virtual void backendCurrentVideoTrackChanged(TrackIndex) = 0;
+ virtual void backendCurrentAudioTrackChanged(TrackIndex) = 0;
+ virtual void backendCurrentSubtitleTrackChanged(TrackIndex) = 0;
+
+ struct Chapter {
+ QString title;
+ TimeStamp startTime;
+ };
+ using ChapterList = QList<Chapter>;
+ virtual void backendChaptersChanged(const ChapterList &chapters) = 0;
+};
+
+class PlayerRendererInterface {
+public:
+ virtual ~PlayerRendererInterface() = default;
+ virtual void rendererSinkSet(VideoUpdateInterface *) = 0;
+ virtual void rendererReady() = 0;
+};
+
+class VideoRendererBase {
+public:
+ VideoRendererBase() = default;
+ VideoRendererBase(const VideoRendererBase &) = delete;
+ VideoRendererBase &operator=(const VideoRendererBase &) = delete;
+ virtual ~VideoRendererBase() = default;
+ virtual void render(QOpenGLFramebufferObject *) = 0;
+};
+
+#endif // PLAYERPLUGININTERFACE_H
--- /dev/null
+#ifndef UIPLUGINBASE_H
+#define UIPLUGINBASE_H
+
+#include <QObject>
+
+class UiInstance {
+public:
+ virtual ~UiInstance() = default;
+};
+
+class UiPluginBase {
+public:
+ virtual ~UiPluginBase() = default;
+
+ virtual UiInstance *createUi(QObject *player, QObject *settings,
+ QObject *parent = nullptr) = 0;
+};
+
+#define ANIPLAYER_UI_PLUGIN_INTERFACE_IID "org.aptx.aniplayer.UiPluginInterface"
+
+Q_DECLARE_INTERFACE(UiPluginBase, ANIPLAYER_UI_PLUGIN_INTERFACE_IID)
+
+#endif // UIPLUGINBASE_H
--- /dev/null
+project(uiplugins)
+
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/uiplugins)
+
+if (WITH_DESKTOP_UI)
+ add_subdirectory(ui_desktop_qml_default)
+endif()
--- /dev/null
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+project(ui_desktop_qml_default)
+
+find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+ Core
+ Gui
+ Qml
+ Quick
+)
+
+set(ui_desktop_qml_default_LIBS
+ Qt5::Core
+ Qt5::Gui
+ Qt5::Qml
+ Qt5::Quick
+ pluginapi
+)
+
+set(ui_desktop_qml_default_SOURCES
+ uidesktopqmldefault.cpp
+ timeformatter.cpp
+
+ qml.qrc
+)
+
+set(ui_desktop_qml_default_HEADERS
+ ui_desktop_qml_default_global.h
+ uidesktopqmldefault.h
+ timeformatter.h
+)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_library(ui_desktop_qml_default MODULE
+ ${ui_desktop_qml_default_SOURCES}
+ ${ui_desktop_qml_default_HEADERS}
+)
+
+set_property(TARGET ui_desktop_qml_default PROPERTY CXX_STANDARD 14)
+set_property(TARGET ui_desktop_qml_default PROPERTY OUTPUT_NAME "ui_desktop_qml_default")
+target_link_libraries(ui_desktop_qml_default ${ui_desktop_qml_default_LIBS})
+
+add_definitions(-DUI_DESKTOP_QML_DEFAULT_LIBRARY)
+
+if(WIN32)
+ set(INSTALL_DESTINATION "aniplayer/uiplugins")
+else()
+ set(INSTALL_DESTINATION "lib${LIB_SUFFIX}/aniplayer/uiplugins")
+endif()
+
+install(TARGETS ui_desktop_qml_default
+ LIBRARY DESTINATION ${INSTALL_DESTINATION}
+ ARCHIVE DESTINATION ${INSTALL_DESTINATION}
+)
+install(FILES $<TARGET_PDB_FILE:ui_desktop_qml_default>
+ DESTINATION ${INSTALL_DESTINATION} OPTIONAL
+)