chore: drop windows-specific code

This commit is contained in:
dela
2026-06-10 16:33:50 +08:00
parent 012d165b81
commit 4c783ab9ea
20 changed files with 24 additions and 588 deletions

View File

@@ -81,7 +81,6 @@ endfunction()
# ========================================== # ==========================================
# 允许通过缓存变量或环境变量提供 Qt 安装路径 # 允许通过缓存变量或环境变量提供 Qt 安装路径
# Windows 未显式指定时仍会尝试兼容现有本地默认路径
# ========================================== # ==========================================
set(QEMBY_QT_ROOT "" CACHE PATH set(QEMBY_QT_ROOT "" CACHE PATH
"Optional Qt installation root or CMake prefix path") "Optional Qt installation root or CMake prefix path")

View File

@@ -17,13 +17,6 @@ function(qemby_append_default_qt_prefixes)
) )
endif() endif()
if(WIN32)
list(APPEND _qemby_qt_prefixes
"E:/Qt6/6.9.2/msvc2022_64"
"E:/Qt6/6.9.2/msvc2022_64/lib/cmake"
)
endif()
foreach(_qemby_qt_prefix IN LISTS _qemby_qt_prefixes) foreach(_qemby_qt_prefix IN LISTS _qemby_qt_prefixes)
if(EXISTS "${_qemby_qt_prefix}") if(EXISTS "${_qemby_qt_prefix}")
list(APPEND CMAKE_PREFIX_PATH "${_qemby_qt_prefix}") list(APPEND CMAKE_PREFIX_PATH "${_qemby_qt_prefix}")
@@ -42,26 +35,6 @@ function(qemby_link_libmpv target)
message(FATAL_ERROR "qemby_link_libmpv: target '${target}' does not exist") message(FATAL_ERROR "qemby_link_libmpv: target '${target}' does not exist")
endif() endif()
if(WIN32)
set(_qemby_mpv_root "${CMAKE_SOURCE_DIR}/libs/libmpv")
set(_qemby_mpv_include_dir "${_qemby_mpv_root}/include")
find_library(MPV_LIBRARY
NAMES mpv libmpv mpv-2 libmpv-2
PATHS "${_qemby_mpv_root}/lib"
NO_DEFAULT_PATH
)
if(NOT MPV_LIBRARY OR NOT EXISTS "${_qemby_mpv_include_dir}/mpv/client.h")
message(FATAL_ERROR
"Could not find bundled libmpv. Place the libmpv SDK under libs/libmpv.")
endif()
target_include_directories("${target}" PRIVATE "${_qemby_mpv_include_dir}")
target_link_libraries("${target}" PRIVATE "${MPV_LIBRARY}")
return()
endif()
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(MPV REQUIRED IMPORTED_TARGET mpv) pkg_check_modules(MPV REQUIRED IMPORTED_TARGET mpv)
target_link_libraries("${target}" PRIVATE PkgConfig::MPV) target_link_libraries("${target}" PRIVATE PkgConfig::MPV)

View File

@@ -10,13 +10,6 @@ set(APP_QRC_FILES resources/resources.qrc)
file(GLOB_RECURSE APP_HEADERS CONFIGURE_DEPENDS "*.h") file(GLOB_RECURSE APP_HEADERS CONFIGURE_DEPENDS "*.h")
file(GLOB_RECURSE APP_SOURCES CONFIGURE_DEPENDS "*.cpp") file(GLOB_RECURSE APP_SOURCES CONFIGURE_DEPENDS "*.cpp")
# ==========================================
# 平台原生资源配置 (如 Windows .exe 图标)
# ==========================================
if(WIN32)
set(APP_NATIVE_RESOURCES qEmbyApp.rc)
endif()
qt_add_executable(qEmbyApp qt_add_executable(qEmbyApp
MANUAL_FINALIZATION MANUAL_FINALIZATION
@@ -24,12 +17,10 @@ qt_add_executable(qEmbyApp
${APP_SOURCES} ${APP_SOURCES}
${TS_FILES} ${TS_FILES}
${APP_QRC_FILES} ${APP_QRC_FILES}
${APP_NATIVE_RESOURCES} # <-- 将 .rc 资源文件加入编译列表
) )
# ========================================== # ==========================================
# 集成 libmpv 播放器核心 # 集成 libmpv 播放器核心
# Windows 使用仓库内置 libmpv
# Linux / macOS 优先使用系统安装的 libmpv # Linux / macOS 优先使用系统安装的 libmpv
# ========================================== # ==========================================
qemby_link_libmpv(qEmbyApp) qemby_link_libmpv(qEmbyApp)
@@ -121,7 +112,7 @@ else()
target_sources(qEmbyApp PRIVATE ${QM_FILES}) target_sources(qEmbyApp PRIVATE ${QM_FILES})
endif() endif()
# 4. 设置平台属性 (Windows 和 macOS) # 4. 设置平台属性
if(${QT_VERSION} VERSION_LESS 6.1.0) if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.hl.qEmby) set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.hl.qEmby)
endif() endif()
@@ -132,7 +123,6 @@ set_target_properties(qEmbyApp PROPERTIES
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
# MACOSX_BUNDLE_ICON_FILE app.icns # 如果未来需要适配 macOS 图标,取消此注释 # MACOSX_BUNDLE_ICON_FILE app.icns # 如果未来需要适配 macOS 图标,取消此注释
) )
@@ -157,31 +147,3 @@ if(QT_VERSION_MAJOR EQUAL 6)
# 注意:目标从 qEmby 改为 qEmbyApp # 注意:目标从 qEmby 改为 qEmbyApp
qt_finalize_executable(qEmbyApp) qt_finalize_executable(qEmbyApp)
endif() endif()
# ==========================================
# 终极防弹方案:调用 windeployqt 自动补全所有 Qt 依赖
# ==========================================
if(WIN32)
# 找到 Qt 官方的部署工具
set(_windeployqt_hints)
if(QEMBY_QT_ROOT)
list(APPEND _windeployqt_hints "${QEMBY_QT_ROOT}/bin")
endif()
if(DEFINED ENV{QTDIR} AND NOT "$ENV{QTDIR}" STREQUAL "")
list(APPEND _windeployqt_hints "$ENV{QTDIR}/bin")
endif()
list(APPEND _windeployqt_hints "E:/Qt6/6.9.2/msvc2022_64/bin")
list(REMOVE_DUPLICATES _windeployqt_hints)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt PATHS ${_windeployqt_hints})
if(WINDEPLOYQT_EXECUTABLE)
# 在 qEmbyApp 编译完成后的那一刻,自动执行该工具
add_custom_command(TARGET qEmbyApp POST_BUILD
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:qEmbyApp>
COMMENT "正在召唤 windeployqt 自动补全所有的 Qt DLL 和底层插件..."
)
else()
message(WARNING "未找到 windeployqt自动部署失败")
endif()
endif()

View File

@@ -8,43 +8,10 @@
#include <widgetframe/windowbar.h> #include <widgetframe/windowbar.h>
#include <widgetframe/windowbutton.h> #include <widgetframe/windowbutton.h>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
namespace {
#ifdef Q_OS_WIN
using DwmSetWindowAttributePtr =
HRESULT(WINAPI *)(HWND, DWORD, LPCVOID, DWORD);
void setWindowTransitionsDisabled(WId windowId, bool disabled)
{
static const HMODULE dwmapi = LoadLibraryW(L"dwmapi.dll");
if (!dwmapi || !windowId) {
return;
}
static const auto dwmSetWindowAttribute =
reinterpret_cast<DwmSetWindowAttributePtr>(
GetProcAddress(dwmapi, "DwmSetWindowAttribute"));
if (!dwmSetWindowAttribute) {
return;
}
constexpr DWORD kDwmwaTransitionsForcedDisabled = 3;
const BOOL value = disabled ? TRUE : FALSE;
dwmSetWindowAttribute(reinterpret_cast<HWND>(windowId),
kDwmwaTransitionsForcedDisabled,
&value, sizeof(value));
}
#endif
}
ModernDialogBase::ModernDialogBase(QWidget *parent, ModernDialogBase::ModernDialogBase(QWidget *parent,
bool disableNativeTransitions) bool disableNativeTransitions)
: QDialog(parent) { : QDialog(parent) {
Q_UNUSED(disableNativeTransitions);
setWindowFlag(Qt::WindowContextHelpButtonHint, false); setWindowFlag(Qt::WindowContextHelpButtonHint, false);
@@ -101,14 +68,6 @@ ModernDialogBase::ModernDialogBase(QWidget *parent,
agent->setSystemButton(QWK::WindowAgentBase::Close, closeBtn); agent->setSystemButton(QWK::WindowAgentBase::Close, closeBtn);
#endif #endif
#ifdef Q_OS_WIN
if (disableNativeTransitions) {
setWindowTransitionsDisabled(winId(), true);
}
#else
Q_UNUSED(disableNativeTransitions);
#endif
m_contentLayout = new QVBoxLayout(); m_contentLayout = new QVBoxLayout();
m_contentLayout->setContentsMargins(20, 10, 20, 20); m_contentLayout->setContentsMargins(20, 10, 20, 20);

View File

@@ -10,10 +10,6 @@
#include <config/config_keys.h> #include <config/config_keys.h>
#include <QStandardPaths> #include <QStandardPaths>
#include <QRegularExpression> #include <QRegularExpression>
#ifdef Q_OS_WIN
#include <QThread>
#include <windows.h>
#endif
QAtomicInt MpvController::s_warmedUp(0); QAtomicInt MpvController::s_warmedUp(0);
@@ -56,7 +52,7 @@ void MpvController::warmupOnce() {
} }
qDebug() << "[MpvController::warmupOnce] dispatch mpv warmup to worker thread" qDebug() << "[MpvController::warmupOnce] dispatch mpv warmup to worker thread"
<< "(preload libmpv DLLs + FFmpeg codec tables to avoid first-play UI freeze)"; << "(preload libmpv + FFmpeg codec tables to avoid first-play UI freeze)";
@@ -93,7 +89,7 @@ void MpvController::warmupOnce() {
qDebug() << "[MpvController::warmupOnce] total elapsed" << timer.elapsed() << "ms" qDebug() << "[MpvController::warmupOnce] total elapsed" << timer.elapsed() << "ms"
<< "(libmpv DLLs + codec tables now resident in process memory;" << "(libmpv + codec tables now resident in process memory;"
<< "next mpv_initialize will run on hot path)"; << "next mpv_initialize will run on hot path)";
}); });
} }
@@ -153,22 +149,6 @@ bool MpvController::init() {
QString hwdec = ConfigStore::instance()->get<QString>(ConfigKeys::PlayerHwDec, "auto-copy"); QString hwdec = ConfigStore::instance()->get<QString>(ConfigKeys::PlayerHwDec, "auto-copy");
#ifdef Q_OS_WIN
mpv_set_option_string(m_mpv, "gpu-api", "opengl");
mpv_set_option_string(m_mpv, "opengl-es", "no");
bool isRDP = GetSystemMetrics(SM_REMOTESESSION) != 0;
if (isRDP) {
hwdec = "no";
mpv_set_option_string(m_mpv, "profile", "sw-fast");
mpv_set_option_string(m_mpv, "gpu-dumb-mode", "yes");
mpv_set_option_string(m_mpv, "opengl-pbo", "no");
mpv_set_option_string(m_mpv, "dither-depth", "no");
}
#endif
mpv_set_option_string(m_mpv, "hwdec", hwdec.toUtf8().constData()); mpv_set_option_string(m_mpv, "hwdec", hwdec.toUtf8().constData());

View File

@@ -12,19 +12,7 @@
#include "managers/languagemanager.h" #include "managers/languagemanager.h"
#include "managers/logmanager.h" #include "managers/logmanager.h"
#ifdef Q_OS_WIN
#include <windows.h>
#endif
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
#ifdef Q_OS_WIN
bool isRDP = GetSystemMetrics(SM_REMOTESESSION) != 0;
if (isRDP) {
qputenv("QT_OPENGL", "software");
}
#endif
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
const QByteArray qpaPlatform = qgetenv("QT_QPA_PLATFORM"); const QByteArray qpaPlatform = qgetenv("QT_QPA_PLATFORM");
const QByteArray forceXcb = qgetenv("QEMBY_FORCE_XCB").toLower(); const QByteArray forceXcb = qgetenv("QEMBY_FORCE_XCB").toLower();

View File

@@ -637,22 +637,7 @@ bool DownloadManager::openContainingFolder(const QString& recordId) const
<< "| filePath:" << fileInfo.absoluteFilePath() << "| filePath:" << fileInfo.absoluteFilePath()
<< "| directory:" << directory; << "| directory:" << directory;
#if defined(Q_OS_WIN) #if defined(Q_OS_MACOS)
if (fileInfo.exists() && fileInfo.isFile()) {
const bool started = QProcess::startDetached(
QStringLiteral("explorer.exe"),
{QStringLiteral("/select,"),
QDir::toNativeSeparators(fileInfo.absoluteFilePath())});
if (started) {
return true;
}
qWarning() << "[DownloadManager] Failed to launch Explorer with"
" file selection"
<< "| recordId:" << recordId
<< "| filePath:" << fileInfo.absoluteFilePath();
}
#elif defined(Q_OS_MACOS)
if (fileInfo.exists() && fileInfo.isFile()) { if (fileInfo.exists() && fileInfo.isFile()) {
const bool started = QProcess::startDetached( const bool started = QProcess::startDetached(
QStringLiteral("open"), QStringLiteral("open"),

View File

@@ -2,16 +2,10 @@
#include <config/config_keys.h> #include <config/config_keys.h>
#include <config/configstore.h> #include <config/configstore.h>
#include <QDir> #include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QSet>
#include <QStandardPaths> #include <QStandardPaths>
#ifdef Q_OS_WIN
#include <QSettings>
#endif
QList<DetectedPlayer> ExternalPlayerDetector::detect() { QList<DetectedPlayer> ExternalPlayerDetector::detect() {
QList<DetectedPlayer> result; QList<DetectedPlayer> result;
@@ -27,110 +21,7 @@ QList<DetectedPlayer> ExternalPlayerDetector::detect() {
} }
}; };
#ifdef Q_OS_WIN #if defined(Q_OS_MAC)
auto tryRegistry = [&](const QString &name, const QString &regKey,
const QString &valueName,
const QString &exeName = {}) {
QSettings reg(regKey, QSettings::NativeFormat);
QString val = reg.value(valueName).toString();
if (val.isEmpty())
return;
QString fullPath = val;
if (!exeName.isEmpty() && QFileInfo(val).isDir()) {
fullPath = val + "/" + exeName;
}
if (QFile::exists(fullPath)) {
result.append({name, QDir::toNativeSeparators(fullPath)});
}
};
tryRegistry(
"PotPlayer",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
"Paths\\PotPlayerMini64.exe",
".", "");
if (result.isEmpty() || result.last().name != "PotPlayer") {
tryRegistry("PotPlayer",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\DAUM\\PotPlayer64",
"ProgramFolder", "PotPlayerMini64.exe");
}
tryRegistry("VLC", "HKEY_LOCAL_MACHINE\\SOFTWARE\\VideoLAN\\VLC",
"InstallDir", "vlc.exe");
tryRegistry(
"MPC-HC",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
"Paths\\mpc-hc64.exe",
".", "");
if (result.isEmpty() || result.last().name != "MPC-HC") {
tryRegistry("MPC-HC",
"HKEY_LOCAL_"
"MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
"Paths\\mpc-hc.exe",
".", "");
}
tryRegistry(
"MPC-BE",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
"Paths\\mpc-be64.exe",
".", "");
if (result.isEmpty() || result.last().name != "MPC-BE") {
tryRegistry("MPC-BE",
"HKEY_LOCAL_"
"MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
"Paths\\mpc-be.exe",
".", "");
}
if (result.isEmpty() || result.last().name != "MPC-BE") {
QStringList beDirs;
for (const auto &drive : QDir::drives()) {
QString d = drive.absolutePath();
beDirs << d + "Program Files/MPC-BE x64" << d + "Program Files/MPC-BE"
<< d + "Program Files (x86)/MPC-BE";
}
tryDetect("MPC-BE", {"mpc-be64.exe", "mpc-be.exe"}, beDirs);
}
{
QString pathMpv = QStandardPaths::findExecutable("mpv.exe");
if (!pathMpv.isEmpty()) {
result.append({"MPV", QDir::toNativeSeparators(pathMpv)});
}
QSet<QString> foundPaths;
if (!pathMpv.isEmpty())
foundPaths.insert(QDir::toNativeSeparators(pathMpv));
for (const auto &drive : QDir::drives()) {
QString d = drive.absolutePath();
QStringList searchRoots = {d + "Program Files",
d + "Program Files (x86)"};
for (const auto &root : searchRoots) {
QDir rootDir(root);
if (!rootDir.exists())
continue;
QStringList mpvDirs = rootDir.entryList({"mpv*"}, QDir::Dirs);
for (const auto &sub : mpvDirs) {
QString exePath = root + "/" + sub + "/mpv.exe";
if (QFile::exists(exePath)) {
QString native = QDir::toNativeSeparators(exePath);
if (!foundPaths.contains(native)) {
foundPaths.insert(native);
QString label = QString("MPV (%1)").arg(sub);
result.append({label, native});
}
}
}
}
}
}
#elif defined(Q_OS_MAC)
tryDetect("MPV", {"mpv"}); tryDetect("MPV", {"mpv"});
tryDetect("VLC", {"vlc"}, {"/Applications/VLC.app/Contents/MacOS"}); tryDetect("VLC", {"vlc"}, {"/Applications/VLC.app/Contents/MacOS"});
tryDetect("IINA", {"iina"}, {"/Applications/IINA.app/Contents/MacOS"}); tryDetect("IINA", {"iina"}, {"/Applications/IINA.app/Contents/MacOS"});

View File

@@ -24,13 +24,7 @@ ExternalPlayerIPC* ExternalPlayerIPC::create(PlayerType type, const QString& ipc
return new MpvIPC(ipcEndpoint, parent); return new MpvIPC(ipcEndpoint, parent);
case PlayerType::VLC: case PlayerType::VLC:
return new EstimationIPC(parent);
#ifdef Q_OS_WIN
case PlayerType::MPC_HC:
return new MpcSlaveIPC(parent);
#endif
case PlayerType::MPC_BE:
default: default:
return new EstimationIPC(parent); return new EstimationIPC(parent);
@@ -293,136 +287,6 @@ void VlcRcIPC::onReadyRead()
} }
#ifdef Q_OS_WIN
#include <Windows.h>
namespace MpcCmd {
constexpr DWORD CMD_CURRENTPOSITION = 0x50000007;
constexpr DWORD CMD_NOWPLAYING = 0x50000003;
constexpr DWORD CMD_PLAYMODE = 0x50000004;
constexpr DWORD CMD_NOTIFYSEEK = 0x50000008;
constexpr DWORD CMD_NOTIFYENDSTREAM = 0x50000009;
constexpr DWORD CMD_GETCURRENTPOSITION = 0xA0003004;
}
MpcSlaveWindow::MpcSlaveWindow(QWidget* parent)
: QWidget(parent)
{
setFixedSize(1, 1);
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setAttribute(Qt::WA_ShowWithoutActivating);
winId();
}
bool MpcSlaveWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
if (eventType == "windows_generic_MSG") {
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_COPYDATA) {
COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
if (!cds) return false;
QString data = QString::fromWCharArray(
reinterpret_cast<const wchar_t*>(cds->lpData),
cds->cbData / sizeof(wchar_t));
if (data.endsWith(QChar('\0')))
data.chop(1);
switch (cds->dwData) {
case MpcCmd::CMD_CURRENTPOSITION:
case MpcCmd::CMD_NOTIFYSEEK: {
bool ok;
double seconds = data.toDouble(&ok);
if (!ok) {
QStringList parts = data.split(':');
if (parts.size() == 3) {
seconds = parts[0].toDouble() * 3600 + parts[1].toDouble() * 60 + parts[2].toDouble();
ok = true;
}
}
if (ok && seconds >= 0.0) {
long long posMs = static_cast<long long>(seconds * 1000);
Q_EMIT positionReceived(posMs);
}
if (result) *result = 1;
return true;
}
case MpcCmd::CMD_NOTIFYENDSTREAM:
Q_EMIT playbackEnded();
if (result) *result = 1;
return true;
default:
break;
}
}
}
return QWidget::nativeEvent(eventType, message, result);
}
MpcSlaveIPC::MpcSlaveIPC(QObject* parent)
: ExternalPlayerIPC(parent)
{
}
MpcSlaveIPC::~MpcSlaveIPC()
{
stop();
}
void MpcSlaveIPC::start(long long startPositionTicks)
{
m_lastPositionTicks = startPositionTicks;
m_window = new MpcSlaveWindow();
connect(m_window, &MpcSlaveWindow::positionReceived, this, [this](long long posMs) {
m_lastPositionTicks = posMs * 10000LL;
Q_EMIT positionUpdated(m_lastPositionTicks);
});
}
void MpcSlaveIPC::stop()
{
if (m_window) {
m_window->deleteLater();
m_window = nullptr;
}
}
long long MpcSlaveIPC::currentPositionTicks() const
{
return m_lastPositionTicks;
}
QString MpcSlaveIPC::hwndString() const
{
if (m_window)
return QString::number(static_cast<quintptr>(m_window->winId()));
return {};
}
#endif
EstimationIPC::EstimationIPC(QObject* parent) EstimationIPC::EstimationIPC(QObject* parent)
: ExternalPlayerIPC(parent) : ExternalPlayerIPC(parent)
{ {

View File

@@ -15,9 +15,6 @@ enum class PlayerType {
MPV, MPV,
IINA, IINA,
VLC, VLC,
PotPlayer,
MPC_HC,
MPC_BE,
MPC_Qt, MPC_Qt,
Unknown Unknown
}; };
@@ -120,50 +117,6 @@ private:
#ifdef Q_OS_WIN
#include <QWidget>
class MpcSlaveWindow : public QWidget
{
Q_OBJECT
public:
explicit MpcSlaveWindow(QWidget* parent = nullptr);
signals:
void positionReceived(long long positionMs);
void playbackEnded();
protected:
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
};
class MpcSlaveIPC : public ExternalPlayerIPC
{
Q_OBJECT
public:
explicit MpcSlaveIPC(QObject* parent = nullptr);
~MpcSlaveIPC() override;
void start(long long startPositionTicks) override;
void stop() override;
long long currentPositionTicks() const override;
bool isPrecise() const override { return true; }
QString hwndString() const;
private:
MpcSlaveWindow* m_window = nullptr;
long long m_lastPositionTicks = 0;
};
#endif
class EstimationIPC : public ExternalPlayerIPC class EstimationIPC : public ExternalPlayerIPC
{ {
Q_OBJECT Q_OBJECT

View File

@@ -151,14 +151,8 @@ PlayerType PlaybackManager::identifyPlayerType(const QString& playerPath)
{ {
QString baseName = QFileInfo(playerPath).baseName().toLower(); QString baseName = QFileInfo(playerPath).baseName().toLower();
if (baseName.contains("potplayer"))
return PlayerType::PotPlayer;
if (baseName == "vlc") if (baseName == "vlc")
return PlayerType::VLC; return PlayerType::VLC;
if (baseName.contains("mpc-hc") || baseName == "mpc-hc64")
return PlayerType::MPC_HC;
if (baseName.contains("mpc-be") || baseName == "mpc-be64")
return PlayerType::MPC_BE;
if (baseName == "mpv") if (baseName == "mpv")
return PlayerType::MPV; return PlayerType::MPV;
if (baseName == "iina") if (baseName == "iina")
@@ -217,11 +211,7 @@ QString PlaybackManager::generateIpcEndpoint(PlayerType type)
switch (type) { switch (type) {
case PlayerType::MPV: case PlayerType::MPV:
case PlayerType::IINA: case PlayerType::IINA:
#ifdef Q_OS_WIN
return QString("\\\\.\\pipe\\qemby-mpv-%1").arg(pid);
#else
return QString("/tmp/qemby-mpv-%1.sock").arg(pid); return QString("/tmp/qemby-mpv-%1.sock").arg(pid);
#endif
case PlayerType::VLC: { case PlayerType::VLC: {
int port = 42900 + static_cast<int>(pid % 1000); int port = 42900 + static_cast<int>(pid % 1000);
@@ -282,12 +272,6 @@ QStringList PlaybackManager::buildPlayerArgs(PlayerType type,
args << "--mpv-sid=no"; args << "--mpv-sid=no";
break; break;
case PlayerType::PotPlayer:
if (startPositionTicks > 0)
args << QString("/seek=%1").arg(timeStr);
break;
case PlayerType::VLC: case PlayerType::VLC:
if (startPositionTicks > 0) if (startPositionTicks > 0)
args << QString("--start-time=%1").arg(static_cast<int>(seconds)); args << QString("--start-time=%1").arg(static_cast<int>(seconds));
@@ -297,16 +281,6 @@ QStringList PlaybackManager::buildPlayerArgs(PlayerType type,
args << QString("--sub-track=%1").arg(relSub); args << QString("--sub-track=%1").arg(relSub);
break; break;
case PlayerType::MPC_HC:
if (startPositionTicks > 0)
args << "/startpos" << timeStr;
break;
case PlayerType::MPC_BE:
if (startPositionTicks > 0)
args << "/startpos" << timeStr;
break;
default: default:
break; break;
} }
@@ -543,9 +517,6 @@ void PlaybackManager::launchExternalPlayer(const QString& mediaId, const QString
if (isLocalPath) { if (isLocalPath) {
qDebug() << "[PlaybackManager] Detected local path, adapting format..."; qDebug() << "[PlaybackManager] Detected local path, adapting format...";
#ifdef Q_OS_WIN
actualStreamUrl.replace('/', '\\');
#endif
switch (playerType) { switch (playerType) {
case PlayerType::MPV: case PlayerType::MPV:
case PlayerType::IINA: case PlayerType::IINA:
@@ -570,20 +541,6 @@ void PlaybackManager::launchExternalPlayer(const QString& mediaId, const QString
m_currentMediaId = mediaId; m_currentMediaId = mediaId;
m_currentMediaSourceId = mediaSourceId; m_currentMediaSourceId = mediaSourceId;
#ifdef Q_OS_WIN
if (playerType == PlayerType::MPC_HC) {
auto* mpcIpc = new MpcSlaveIPC(this);
mpcIpc->start(startPositionTicks);
QString hwnd = mpcIpc->hwndString();
if (!hwnd.isEmpty()) {
args.insert(args.size() - 1, "/slave");
args.insert(args.size() - 1, hwnd);
}
m_ipc = mpcIpc;
} else
#endif
{ {
m_ipc = ExternalPlayerIPC::create(playerType, ipcEndpoint, this); m_ipc = ExternalPlayerIPC::create(playerType, ipcEndpoint, this);
m_ipc->start(startPositionTicks); m_ipc->start(startPositionTicks);

View File

@@ -12,7 +12,6 @@
#include <QPalette> #include <QPalette>
#include <QPixmap> #include <QPixmap>
#include <QPainter> #include <QPainter>
#include <QSettings>
#include <QProcess> #include <QProcess>
#include <QRegularExpression> #include <QRegularExpression>
#include "config/configstore.h" #include "config/configstore.h"
@@ -162,13 +161,6 @@ ThemeManager::Theme ThemeManager::detectSystemTheme()
auto scheme = QGuiApplication::styleHints()->colorScheme(); auto scheme = QGuiApplication::styleHints()->colorScheme();
return (scheme == Qt::ColorScheme::Light) ? Light : Dark; return (scheme == Qt::ColorScheme::Light) ? Light : Dark;
#elif defined(Q_OS_WIN)
QSettings reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
QSettings::NativeFormat);
QVariant val = reg.value("AppsUseLightTheme", 0);
return val.toInt() == 1 ? Light : Dark;
#elif defined(Q_OS_MACOS) #elif defined(Q_OS_MACOS)

View File

@@ -1,7 +0,0 @@
// This is the complete Windows Resource file for qEmbyApp.
// IDI_ICON1 是图标资源的 ID101 是任意不冲突的整数。
// ICON 声明资源类型为图标。
// "qEmbyApp.ico" 是图标文件的相对路径(相对于此 .rc 文件)。
IDI_ICON1 ICON DISCARDABLE "resources/qEmbyApp.ico"

View File

@@ -2038,10 +2038,6 @@ Cette opération supprimera le fichier journal actuel ainsi que les sauvegardes
<context> <context>
<name>PagePlayer</name> <name>PagePlayer</name>
<message>
<source>D3D11VA (Windows)</source>
<translation>D3D11VA (Windows)</translation>
</message>
<message> <message>
<source>Select GPU acceleration API for video rendering</source> <source>Select GPU acceleration API for video rendering</source>
<translation>Sélectionner l'API d'accélération GPU pour le rendu vidéo</translation> <translation>Sélectionner l'API d'accélération GPU pour le rendu vidéo</translation>
@@ -2507,12 +2503,12 @@ Cette action ne peut pas être annulée.</translation>
<translation>Auto</translation> <translation>Auto</translation>
</message> </message>
<message> <message>
<source>D3D11VA</source> <source>VAAPI</source>
<translation>D3D11VA</translation> <translation>VAAPI</translation>
</message> </message>
<message> <message>
<source>DXVA2</source> <source>VDPAU</source>
<translation>DXVA2</translation> <translation>VDPAU</translation>
</message> </message>
<message> <message>
<source>CUDA (NVIDIA)</source> <source>CUDA (NVIDIA)</source>

View File

@@ -2298,10 +2298,6 @@ This will remove the current log and rotated backups. This action cannot be undo
<context> <context>
<name>PagePlayer</name> <name>PagePlayer</name>
<message>
<source>D3D11VA (Windows)</source>
<translation>D3D11VA (Windows)</translation>
</message>
<message> <message>
<source>Select GPU acceleration API for video rendering</source> <source>Select GPU acceleration API for video rendering</source>
<translation> GPU </translation> <translation> GPU </translation>
@@ -2819,12 +2815,12 @@ This action cannot be undone.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>D3D11VA</source> <source>VAAPI</source>
<translation>D3D11VA</translation> <translation>VAAPI</translation>
</message> </message>
<message> <message>
<source>DXVA2</source> <source>VDPAU</source>
<translation>DXVA2</translation> <translation>VDPAU</translation>
</message> </message>
<message> <message>
<source>CUDA (NVIDIA)</source> <source>CUDA (NVIDIA)</source>

View File

@@ -2376,7 +2376,7 @@ QProgressBar#detail-progress-bar {
max-height: 2px; max-height: 2px;
background-color: rgba(255, 255, 255, 0.12); background-color: rgba(255, 255, 255, 0.12);
border: 1px solid transparent; border: 1px solid transparent;
/* 核心:用透明边框强制覆盖 Windows 原生样式引擎 */ /* 核心:用透明边框强制覆盖原生样式引擎 */
border-radius: 1px; border-radius: 1px;
} }

View File

@@ -2048,7 +2048,7 @@ QPushButton#gallery-nav-btn:pressed {
QPushButton#section-more-btn { QPushButton#section-more-btn {
background: transparent; background: transparent;
color: #0078D7; color: #0078D7;
/* Windows 经典强调色,或替换为系统的 Primary Color */ /* 经典强调色,或替换为系统的 Primary Color */
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
border: none; border: none;
@@ -2450,7 +2450,7 @@ QProgressBar#detail-progress-bar {
max-height: 2px; max-height: 2px;
background-color: rgba(0, 0, 0, 0.12); background-color: rgba(0, 0, 0, 0.12);
border: 1px solid transparent; border: 1px solid transparent;
/* 核心:用透明边框强制覆盖 Windows 原生样式引擎 */ /* 核心:用透明边框强制覆盖原生样式引擎 */
border-radius: 1px; border-radius: 1px;
} }

View File

@@ -3,9 +3,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
#if defined(Q_OS_WIN) #if defined(Q_OS_MACOS)
#include <windows.h>
#elif defined(Q_OS_MACOS)
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <IOKit/pwr_mgt/IOPMLib.h> #include <IOKit/pwr_mgt/IOPMLib.h>
#elif defined(QEMBY_HAS_QT_DBUS) #elif defined(QEMBY_HAS_QT_DBUS)
@@ -22,7 +20,7 @@ bool g_platformInhibited = false;
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
IOPMAssertionID g_displayAssertion = kIOPMNullAssertionID; IOPMAssertionID g_displayAssertion = kIOPMNullAssertionID;
IOPMAssertionID g_systemAssertion = kIOPMNullAssertionID; IOPMAssertionID g_systemAssertion = kIOPMNullAssertionID;
#elif defined(QEMBY_HAS_QT_DBUS) && !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) #elif defined(QEMBY_HAS_QT_DBUS)
enum class DbusInhibitor { enum class DbusInhibitor {
None, None,
FreedesktopScreenSaver, FreedesktopScreenSaver,
@@ -57,18 +55,7 @@ CFStringRef createCFString(const QString &value)
bool activatePlatformInhibition(const QString &reason) bool activatePlatformInhibition(const QString &reason)
{ {
#if defined(Q_OS_WIN) #if defined(Q_OS_MACOS)
const EXECUTION_STATE state =
ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED;
const EXECUTION_STATE previous = SetThreadExecutionState(state);
if (previous == 0) {
qWarning() << "[PowerInhibit] Failed to prevent display sleep on Windows";
return false;
}
qDebug() << "[PowerInhibit] Display sleep inhibited on Windows";
return true;
#elif defined(Q_OS_MACOS)
const QString resolvedReason = inhibitionReason(reason); const QString resolvedReason = inhibitionReason(reason);
CFStringRef reasonRef = createCFString(resolvedReason); CFStringRef reasonRef = createCFString(resolvedReason);
if (!reasonRef) { if (!reasonRef) {
@@ -181,10 +168,7 @@ bool activatePlatformInhibition(const QString &reason)
void deactivatePlatformInhibition() void deactivatePlatformInhibition()
{ {
#if defined(Q_OS_WIN) #if defined(Q_OS_MACOS)
SetThreadExecutionState(ES_CONTINUOUS);
qDebug() << "[PowerInhibit] Display sleep inhibition released on Windows";
#elif defined(Q_OS_MACOS)
if (g_displayAssertion != kIOPMNullAssertionID) { if (g_displayAssertion != kIOPMNullAssertionID) {
IOPMAssertionRelease(g_displayAssertion); IOPMAssertionRelease(g_displayAssertion);
g_displayAssertion = kIOPMNullAssertionID; g_displayAssertion = kIOPMNullAssertionID;

View File

@@ -37,7 +37,6 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QSignalBlocker> #include <QSignalBlocker>
#include <QSet> #include <QSet>
#include <QSettings>
#include <QStringList> #include <QStringList>
#include <QStandardPaths> #include <QStandardPaths>
#include <QTextStream> #include <QTextStream>
@@ -53,8 +52,8 @@ PagePlayer::PagePlayer(QEmbyCore *core, QWidget *parent)
auto *hwCombo = new ModernComboBox(this); auto *hwCombo = new ModernComboBox(this);
hwCombo->addItem(tr("Auto"), "auto-copy"); hwCombo->addItem(tr("Auto"), "auto-copy");
hwCombo->addItem(tr("D3D11VA"), "d3d11va-copy"); hwCombo->addItem(tr("VAAPI"), "vaapi-copy");
hwCombo->addItem(tr("DXVA2"), "dxva2-copy"); hwCombo->addItem(tr("VDPAU"), "vdpau-copy");
hwCombo->addItem(tr("CUDA (NVIDIA)"), "cuda-copy"); hwCombo->addItem(tr("CUDA (NVIDIA)"), "cuda-copy");
hwCombo->addItem(tr("None (Software)"), "no"); hwCombo->addItem(tr("None (Software)"), "no");
m_mainLayout->addWidget( m_mainLayout->addWidget(
@@ -880,21 +879,9 @@ PagePlayer::PagePlayer(QEmbyCore *core, QWidget *parent)
m_mainLayout->addWidget(extTitle); m_mainLayout->addWidget(extTitle);
QStringList supportedExternalPlayers; QStringList supportedExternalPlayers;
#ifdef Q_OS_WIN
supportedExternalPlayers = {QStringLiteral("PotPlayer"),
QStringLiteral("VLC"),
QStringLiteral("MPC-HC"),
QStringLiteral("MPC-BE"),
QStringLiteral("MPV")};
#elif defined(Q_OS_MAC)
supportedExternalPlayers = {QStringLiteral("MPV"),
QStringLiteral("VLC"),
QStringLiteral("IINA")};
#else
supportedExternalPlayers = {QStringLiteral("MPV"), supportedExternalPlayers = {QStringLiteral("MPV"),
QStringLiteral("VLC"), QStringLiteral("VLC"),
QStringLiteral("MPC-Qt")}; QStringLiteral("MPC-Qt")};
#endif
const QString externalPlayerSupportText = const QString externalPlayerSupportText =
tr("Supported players on this platform: %1") tr("Supported players on this platform: %1")
.arg(supportedExternalPlayers.join(QStringLiteral(", "))); .arg(supportedExternalPlayers.join(QStringLiteral(", ")));
@@ -1130,11 +1117,7 @@ PagePlayer::PagePlayer(QEmbyCore *core, QWidget *parent)
if (source == PlayerComboBox::SourceCustom) { if (source == PlayerComboBox::SourceCustom) {
QString filePath = QFileDialog::getOpenFileName( QString filePath = QFileDialog::getOpenFileName(
this, tr("Select External Player"), QString(), this, tr("Select External Player"), QString(),
#ifdef Q_OS_WIN
tr("Executable Files (*.exe)")
#else
tr("All Files (*)") tr("All Files (*)")
#endif
); );
if (!filePath.isEmpty()) { if (!filePath.isEmpty()) {
filePath = QDir::toNativeSeparators(filePath); filePath = QDir::toNativeSeparators(filePath);

View File

@@ -65,29 +65,10 @@ QString compactProductType(QString type)
return type; return type;
} }
int windowsBuildNumber()
{
const QStringList parts = QSysInfo::kernelVersion().split(QLatin1Char('.'));
bool ok = false;
const int build = parts.size() >= 3 ? parts.at(2).toInt(&ok) : 0;
return ok ? build : 0;
}
QString readableOsName() QString readableOsName()
{ {
const QString type = QSysInfo::productType().toLower(); const QString type = QSysInfo::productType().toLower();
const QString version = QSysInfo::productVersion().trimmed(); const QString version = QSysInfo::productVersion().trimmed();
if (type == QStringLiteral("windows"))
{
const int build = windowsBuildNumber();
if (build >= 22000)
return QStringLiteral("Win11");
if (build > 0)
return QStringLiteral("Win10");
return version.isEmpty() ? QStringLiteral("Windows")
: QStringLiteral("Windows%1").arg(version);
}
if (type == QStringLiteral("macos") || type == QStringLiteral("osx")) if (type == QStringLiteral("macos") || type == QStringLiteral("osx"))
return version.isEmpty() ? QStringLiteral("macOS") return version.isEmpty() ? QStringLiteral("macOS")
: QStringLiteral("macOS%1").arg(version); : QStringLiteral("macOS%1").arg(version);