1 | /* |
2 | SPDX-FileCopyrightText: 2024 Akseli Lahtinen <akselmo@akselmo.dev> |
3 | SPDX-License-Identifier: LGPL-2.0-or-later |
4 | */ |
5 | |
6 | #include "global.h" |
7 | #include "standardthumbnailjob_p.h" |
8 | #include <KMacroExpander> |
9 | #include <QImage> |
10 | #include <QProcess> |
11 | #include <QTemporaryFile> |
12 | |
13 | class ThumbnailerExpander : public KMacroExpanderBase |
14 | { |
15 | public: |
16 | explicit ThumbnailerExpander(const QString execString, const int width, const QString inputFile, const QString outputFile) |
17 | : KMacroExpanderBase(QLatin1Char('%')) |
18 | , m_width(width) |
19 | , m_execString(execString) |
20 | , m_inputFile(inputFile) |
21 | , m_outputFile(outputFile) |
22 | { |
23 | QString newString(execString); |
24 | expandMacros(str&: newString); |
25 | auto fullCmd = QProcess::splitCommand(command: newString); |
26 | m_binary = fullCmd.first(); |
27 | fullCmd.removeFirst(); |
28 | m_args = fullCmd; |
29 | } |
30 | |
31 | QString binary() |
32 | { |
33 | return m_binary; |
34 | } |
35 | |
36 | QStringList args() |
37 | { |
38 | return m_args; |
39 | } |
40 | |
41 | private: |
42 | int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; |
43 | const int m_width; |
44 | const QString m_execString; |
45 | const QString m_inputFile; |
46 | const QString m_outputFile; |
47 | QString m_binary; |
48 | QStringList m_args; |
49 | }; |
50 | |
51 | int ThumbnailerExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret) |
52 | { |
53 | uint option = str[pos + 1].unicode(); |
54 | switch (option) { |
55 | case 's': |
56 | ret << QString::number(m_width); |
57 | break; |
58 | case 'i': |
59 | case 'u': |
60 | ret << QStringLiteral(R"("%1")" ).arg(a: m_inputFile); |
61 | break; |
62 | case 'o': |
63 | ret << QStringLiteral(R"("%1")" ).arg(a: m_outputFile); |
64 | break; |
65 | case '%': |
66 | ret = QStringList(QStringLiteral("%" )); |
67 | break; |
68 | default: |
69 | return -2; // subst with same and skip |
70 | } |
71 | return 2; |
72 | } |
73 | |
74 | class Q_DECL_HIDDEN KIO::StandardThumbnailJob::Private |
75 | { |
76 | public: |
77 | explicit Private(const QString &execString, int width, const QString &inputFile, const QString &outputFolder) |
78 | : m_execString(execString) |
79 | , m_width(width) |
80 | , m_inputFile(inputFile) |
81 | , m_outputFolder(outputFolder) |
82 | { |
83 | } |
84 | ~Private() |
85 | { |
86 | } |
87 | |
88 | QString m_execString; |
89 | int m_width; |
90 | QString m_inputFile; |
91 | QString m_outputFolder; |
92 | QProcess *m_proc; |
93 | QTemporaryFile *m_tempFile; |
94 | }; |
95 | |
96 | KIO::StandardThumbnailJob::StandardThumbnailJob(const QString &execString, int width, const QString &inputFile, const QString &outputFolder) |
97 | : d(new Private(execString, width, inputFile, outputFolder)) |
98 | { |
99 | setAutoDelete(true); |
100 | } |
101 | |
102 | KIO::StandardThumbnailJob::~StandardThumbnailJob() = default; |
103 | |
104 | bool KIO::StandardThumbnailJob::StandardThumbnailJob::doKill() |
105 | { |
106 | d->m_proc->kill(); |
107 | return true; |
108 | } |
109 | |
110 | void KIO::StandardThumbnailJob::StandardThumbnailJob::start() |
111 | { |
112 | // Prepare the command |
113 | d->m_tempFile = new QTemporaryFile(QStringLiteral("%1/XXXXXX.png" ).arg(a: d->m_outputFolder)); |
114 | if (!d->m_tempFile->open()) { |
115 | setErrorText(QStringLiteral("Standard Thumbnail Job had an error: could not open temporary file" )); |
116 | setError(KIO::ERR_CANNOT_OPEN_FOR_WRITING); |
117 | emitResult(); |
118 | } |
119 | d->m_tempFile->setAutoRemove(false); |
120 | |
121 | ThumbnailerExpander thumbnailer(d->m_execString, d->m_width, d->m_inputFile, d->m_tempFile->fileName()); |
122 | // Emit data on command exit |
123 | d->m_proc = new QProcess(); |
124 | connect(sender: d->m_proc, signal: &QProcess::finished, context: this, slot: [=, this](const int exitCode, const QProcess::ExitStatus /* exitStatus */) { |
125 | d->m_proc->deleteLater(); |
126 | if (exitCode != 0) { |
127 | setErrorText(QStringLiteral("Standard Thumbnail Job failed with exit code: %1 " ).arg(a: exitCode)); |
128 | setError(KIO::ERR_CANNOT_LAUNCH_PROCESS); |
129 | emitResult(); |
130 | |
131 | // clean temp file |
132 | d->m_tempFile->remove(); |
133 | return; |
134 | } |
135 | Q_EMIT data(job: this, thumb: QImage(d->m_tempFile->fileName())); |
136 | emitResult(); |
137 | |
138 | // clean temp file |
139 | d->m_tempFile->remove(); |
140 | }); |
141 | connect(sender: d->m_proc, signal: &QProcess::errorOccurred, context: this, slot: [=, this](const QProcess::ProcessError error) { |
142 | d->m_proc->deleteLater(); |
143 | setErrorText(QStringLiteral("Standard Thumbnail Job had an error: %1" ).arg(a: error)); |
144 | setError(KIO::ERR_CANNOT_LAUNCH_PROCESS); |
145 | emitResult(); |
146 | |
147 | // clean temp file |
148 | d->m_tempFile->remove(); |
149 | }); |
150 | d->m_proc->start(program: thumbnailer.binary(), arguments: thumbnailer.args()); |
151 | } |
152 | |
153 | #include "moc_standardthumbnailjob_p.cpp" |
154 | |