[multimedia/subtitlecomposer] /: Support opening and saving files from KIO URLs

Mladen Milinkovic <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit dd5f95d5e976fff6803a974982cfeca1fa1dea5a by Mladen Milinkovic.
Committed on 29/07/2026 at 19:30.
Pushed by milinkovic into branch 'master'.

Support opening and saving files from KIO URLs

KIO support was removed in f8280dbcc0b23aed2e55d8db39c220ad900e7825 to
improve local file handling, remove build dependencies, address API
differences between KIO versions, and provide a better user experience
(e.g. by avoiding notifications during file operations).

This allows KIO-FUSE to provide access to network shares and virtual file
systems while continuing to use the local file APIs.

BUGREPORT 523629

M  +1    -1    CMakeLists.txt
M  +1    -1    src/application.h
M  +3    -3    src/application_subtitle.cpp
M  +10   -2    src/formats/formatmanager.cpp
M  +2    -2    src/formats/formatmanager.h
M  +35   -3    src/helpers/commondefs.cpp
M  +8    -0    src/helpers/commondefs.h

https://invent.kde.org/multimedia/subtitlecomposer/-/commit/dd5f95d5e976fff6803a974982cfeca1fa1dea5a

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1a1eb652..0d67a487 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,7 @@ include(ECMAddTests) # build tests
 include(FeatureSummary)
 
 find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
-	Core Widgets Gui Test Qml ${QT_EXTRA_COMPONENTS})
+	Core Widgets Gui Test Qml DBus ${QT_EXTRA_COMPONENTS})
 
 find_package(KF${KF_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS
 	Config ConfigWidgets CoreAddons I18n KIO XmlGui
diff --git a/src/application.h b/src/application.h
index 0473df24..d53a0771 100644
--- a/src/application.h
+++ b/src/application.h
@@ -92,7 +92,7 @@ public slots:
 	void openSubtitle();
 	void reopenSubtitleWithCodec(QTextCodec *codec = nullptr);
 	void demuxTextStream(int textStreamIndex);
-	void openSubtitle(const QUrl &url, bool warnClashingUrls = true);
+	void openSubtitle(QUrl url, bool warnClashingUrls = true);
 	bool saveSubtitle(QTextCodec *codec = nullptr);
 	bool saveSubtitleAs(QTextCodec *codec = nullptr);
 	bool closeSubtitle();
diff --git a/src/application_subtitle.cpp b/src/application_subtitle.cpp
index 34d96895..031e15bb 100644
--- a/src/application_subtitle.cpp
+++ b/src/application_subtitle.cpp
@@ -155,7 +155,7 @@ Application::openSubtitle()
 }
 
 void
-Application::openSubtitle(const QUrl &url, bool warnClashingUrls)
+Application::openSubtitle(QUrl url, bool warnClashingUrls)
 {
 	m_lastSubtitleUrl = url;
 
@@ -173,8 +173,8 @@ Application::openSubtitle(const QUrl &url, bool warnClashingUrls)
 		m_subtitleUrl = url;
 		processSubtitleOpened(codec, m_subtitleFormat);
 
-		if(m_subtitleUrl.isLocalFile() && SCConfig::automaticVideoLoad()) {
-			QFileInfo subtitleFileInfo(m_subtitleUrl.toLocalFile());
+		if(SCConfig::automaticVideoLoad() && System::makeUrlReachable(&url)) {
+			QFileInfo subtitleFileInfo(url.toLocalFile());
 
 			QString subtitleFileName = m_subtitleFileName.toLower();
 			QString videoFileName = QFileInfo(videoPlayer()->filePath()).completeBaseName().toLower();
diff --git a/src/formats/formatmanager.cpp b/src/formats/formatmanager.cpp
index 72579945..0197b7cb 100644
--- a/src/formats/formatmanager.cpp
+++ b/src/formats/formatmanager.cpp
@@ -14,6 +14,7 @@
 #include "application.h"
 #include "dialogs/encodingdetectdialog.h"
 #include "scconfig.h"
+#include "helpers/commondefs.h"
 
 #include "microdvd/microdvdinputformat.h"
 #include "microdvd/microdvdoutputformat.h"
@@ -37,6 +38,7 @@
 #include "youtubecaptions/youtubecaptionsinputformat.h"
 #include "youtubecaptions/youtubecaptionsoutputformat.h"
 
+#include <QDir>
 #include <QFile>
 #include <QFileDevice>
 #include <QFileInfo>
@@ -226,9 +228,12 @@ FormatManager::readText(Subtitle &subtitle, const QUrl &url, bool primary,
 }
 
 FormatManager::Status
-FormatManager::readSubtitle(Subtitle &subtitle, bool primary, const QUrl &url,
+FormatManager::readSubtitle(Subtitle &subtitle, bool primary, QUrl url,
 							QTextCodec **codec, QString *formatName) const
 {
+	if(!url.isLocalFile() && !System::makeUrlReachable(&url))
+		return ERROR;
+
 	Status res = readBinary(subtitle, url, primary, codec, formatName);
 	if(res != ERROR) // when SUCCESS or CANCEL no need to try text formats
 		return res;
@@ -261,7 +266,7 @@ FormatManager::outputNames() const
 }
 
 bool
-FormatManager::writeSubtitle(const Subtitle &subtitle, bool primary, const QUrl &url,
+FormatManager::writeSubtitle(const Subtitle &subtitle, bool primary, QUrl url,
 							 QTextCodec *codec, const QString &formatName, bool overwrite) const
 {
 	const OutputFormat *format = output(formatName);
@@ -278,6 +283,9 @@ FormatManager::writeSubtitle(const Subtitle &subtitle, bool primary, const QUrl
 	if(format == nullptr)
 		return false;
 
+	if(!url.isLocalFile() && !System::makeUrlReachable(&url))
+		return false;
+
 	if(!overwrite && QFile::exists(url.toLocalFile()))
 		return false;
 	QSaveFile file(url.toLocalFile());
diff --git a/src/formats/formatmanager.h b/src/formats/formatmanager.h
index db965cc8..b3379043 100644
--- a/src/formats/formatmanager.h
+++ b/src/formats/formatmanager.h
@@ -37,7 +37,7 @@ public:
 	const InputFormat * input(const QString &name) const;
 	QStringList inputNames() const;
 
-	Status readSubtitle(Subtitle &subtitle, bool primary, const QUrl &url,
+	Status readSubtitle(Subtitle &subtitle, bool primary, QUrl url,
 						QTextCodec **codec, QString *format = nullptr) const;
 
 	bool hasOutput(const QString &name) const;
@@ -45,7 +45,7 @@ public:
 	const OutputFormat * defaultOutput() const;
 	QStringList outputNames() const;
 
-	bool writeSubtitle(const Subtitle &subtitle, bool primary, const QUrl &url,
+	bool writeSubtitle(const Subtitle &subtitle, bool primary, QUrl url,
 					   QTextCodec *codec, const QString &format, bool overwrite) const;
 
 protected:
diff --git a/src/helpers/commondefs.cpp b/src/helpers/commondefs.cpp
index 72eac8e9..b2d68e5a 100644
--- a/src/helpers/commondefs.cpp
+++ b/src/helpers/commondefs.cpp
@@ -10,12 +10,13 @@
 #include <cstdlib>
 #include <climits>
 
-#include <QStringBuilder>
+#include <QDBusInterface>
+#include <QDBusReply>
+#include <QDebug>
 #include <QDir>
 #include <QFileInfo>
-
-#include <QDebug>
 #include <QStandardPaths>
+#include <QStringBuilder>
 
 #ifndef Q_OS_WIN
 #include <unistd.h>
@@ -243,3 +244,34 @@ System::urlIsInside(const QUrl &url, QStringList &path)
 	}
 	return false;
 }
+
+bool
+System::makeUrlReachable(QUrl *url)
+{
+	if(url->isLocalFile())
+		return true;
+
+	QUrl parentUrl = url->adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash);
+	QString filename = url->fileName();
+
+	if(filename.isEmpty()) {
+		qWarning() << "URL does not contain a valid file name:" << url;
+		return false;
+	}
+
+	QDBusInterface kioFuse(
+		QStringLiteral("org.kde.KIOFuse"),
+		QStringLiteral("/org/kde/KIOFuse"),
+		QStringLiteral("org.kde.KIOFuse.VFS"),
+		QDBusConnection::sessionBus()
+	);
+
+	QDBusReply<QString> reply = kioFuse.call(QStringLiteral("mountUrl"), parentUrl.toString());
+	if(!reply.isValid()) {
+		qWarning() << "KIOFuse mount failed:" << reply.error().message();
+		return false;
+	}
+
+	*url = QUrl::fromLocalFile(QDir(reply.value()).filePath(filename));
+	return true;
+}
diff --git a/src/helpers/commondefs.h b/src/helpers/commondefs.h
index 4abc6cb0..effc7a9f 100644
--- a/src/helpers/commondefs.h
+++ b/src/helpers/commondefs.h
@@ -37,6 +37,14 @@ public:
 	static bool isReadable(const QString &path);
 	static bool isWritable(const QString &path);
 
+	/**
+	 * @brief Converts a KIO URL to a local file URL using the KIO-FUSE D-Bus mount.
+	 *        Local file URLs are left unchanged.
+	 * @param url Pointer to the URL to mount. Updated with the local mounted path on success.
+	 * @return true if the URL is already a local file or was successfully mounted; false otherwise.
+	 */
+	static bool makeUrlReachable(QUrl *url);
+
 	static QString homeDir();
 	static QString tempDir();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.