mirror of
https://github.com/jellyfin/jellyfin-desktop.git
synced 2026-10-26 16:45:24 +00:00
Add portable mode for Windows
Detect portable marker file (portable or portable.txt) next to exe and store data/cache in app directory instead of AppData. ZIP package includes marker file for out-of-box portable use.
This commit is contained in:
1 parent
747275054e
commit
3e840b3c8c
4 files changed
+107
-2
No files matched your search
@@ -0,0 +1,41 @@
|
||||
# Prepare portable ZIP contents
|
||||
# Copies installed files to a separate directory with runtime DLLs in root
|
||||
|
||||
set(SOURCE_DIR "@CMAKE_INSTALL_PREFIX@")
|
||||
set(ZIP_DIR "@CMAKE_CURRENT_BINARY_DIR@/portable")
|
||||
set(PROJECT_SOURCE_DIR "@PROJECT_SOURCE_DIR@")
|
||||
|
||||
# Clean and create ZIP staging directory
|
||||
file(REMOVE_RECURSE "${ZIP_DIR}")
|
||||
file(MAKE_DIRECTORY "${ZIP_DIR}")
|
||||
|
||||
# Copy all files except redist folder and vc_redist installer
|
||||
file(GLOB_RECURSE ALL_FILES RELATIVE "${SOURCE_DIR}" "${SOURCE_DIR}/*")
|
||||
foreach(f ${ALL_FILES})
|
||||
# Skip redist folder and VCRedist installer
|
||||
if(f MATCHES "^redist/" OR f STREQUAL "vc_redist.x64.exe")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
get_filename_component(dir "${f}" DIRECTORY)
|
||||
if(dir)
|
||||
file(MAKE_DIRECTORY "${ZIP_DIR}/${dir}")
|
||||
endif()
|
||||
file(COPY "${SOURCE_DIR}/${f}" DESTINATION "${ZIP_DIR}/${dir}")
|
||||
endforeach()
|
||||
|
||||
# Copy runtime DLLs to root (for portable use)
|
||||
set(VCRUNTIME_DIR "${PROJECT_SOURCE_DIR}/deps/vcruntime")
|
||||
if(EXISTS "${VCRUNTIME_DIR}")
|
||||
file(GLOB RUNTIME_DLLS "${VCRUNTIME_DIR}/*.dll")
|
||||
foreach(dll ${RUNTIME_DLLS})
|
||||
file(COPY "${dll}" DESTINATION "${ZIP_DIR}")
|
||||
endforeach()
|
||||
message(STATUS "Bundled VC runtime DLLs for portable package")
|
||||
endif()
|
||||
|
||||
# Create portable marker file
|
||||
file(WRITE "${ZIP_DIR}/portable" "")
|
||||
message(STATUS "Created portable marker file")
|
||||
|
||||
message(STATUS "Portable package prepared in: ${ZIP_DIR}")
|
||||
+9
-1
@@ -193,7 +193,15 @@ int main(int argc, char *argv[])
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// Handle config-dir first (affects where profiles.json is located)
|
||||
// Check for portable mode (marker file next to exe)
|
||||
if (Paths::detectAndEnablePortableMode())
|
||||
{
|
||||
// Portable mode sets its own paths, skip config-dir
|
||||
QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope,
|
||||
Paths::globalDataDir());
|
||||
}
|
||||
|
||||
// Handle config-dir (overrides portable mode if explicitly set)
|
||||
auto configDir = parser.value("config-dir");
|
||||
if (!configDir.isEmpty())
|
||||
{
|
||||
|
||||
+54
-1
@@ -15,7 +15,9 @@
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
static QString g_configDirOverride;
|
||||
static QString g_cacheDirOverride;
|
||||
static QString g_activeProfileId;
|
||||
static bool g_portableMode = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Paths::setConfigDir(const QString& path)
|
||||
@@ -23,6 +25,42 @@ void Paths::setConfigDir(const QString& path)
|
||||
g_configDirOverride = path;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Paths::setCacheDir(const QString& path)
|
||||
{
|
||||
g_cacheDirOverride = path;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Paths::isPortableMode()
|
||||
{
|
||||
return g_portableMode;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Paths::detectAndEnablePortableMode()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QString appDir = QGuiApplication::applicationDirPath();
|
||||
|
||||
// Check for portable marker file
|
||||
if (QFile::exists(appDir + "/portable") || QFile::exists(appDir + "/portable.txt"))
|
||||
{
|
||||
QString dataPath = appDir + "/data";
|
||||
QString cachePath = appDir + "/cache";
|
||||
|
||||
g_portableMode = true;
|
||||
g_configDirOverride = dataPath;
|
||||
g_cacheDirOverride = cachePath;
|
||||
|
||||
qInfo() << "Portable mode enabled, data:" << dataPath;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
static QDir writableLocation(QStandardPaths::StandardLocation loc)
|
||||
{
|
||||
@@ -93,7 +131,22 @@ QString Paths::globalDataDir(const QString& file)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
QString Paths::globalCacheDir(const QString& file)
|
||||
{
|
||||
QDir d = writableLocation(QStandardPaths::GenericCacheLocation);
|
||||
QDir d;
|
||||
|
||||
if (!g_cacheDirOverride.isEmpty())
|
||||
{
|
||||
d = QDir(g_cacheDirOverride);
|
||||
if (!d.mkpath(d.absolutePath()))
|
||||
{
|
||||
qWarning() << "Failed to create cache override directory:" << d.absolutePath();
|
||||
d = writableLocation(QStandardPaths::GenericCacheLocation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d = writableLocation(QStandardPaths::GenericCacheLocation);
|
||||
}
|
||||
|
||||
if (file.isEmpty())
|
||||
return d.absolutePath();
|
||||
return d.filePath(file);
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
namespace Paths
|
||||
{
|
||||
void setConfigDir(const QString& path);
|
||||
void setCacheDir(const QString& path);
|
||||
bool isPortableMode();
|
||||
bool detectAndEnablePortableMode();
|
||||
QString resourceDir(const QString& file = QString());
|
||||
QString socketName(const QString& serverName);
|
||||
QString soundsPath(const QString& sound);
|
||||
|
||||
Reference in new issue
Block a user