summaryrefslogtreecommitdiffstats
path: root/utils/rbutilqt/base/talkfile.cpp
blob: f5fae01a852a0586995abeee2a208bc92b8643e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 *   Copyright (C) 2007 by Dominik Wenger
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "talkfile.h"
#include "rbsettings.h"
#include "Logger.h"

TalkFileCreator::TalkFileCreator(QObject* parent): QObject(parent)
{

}

//! \brief Creates Talkfiles.
//!
//! \param logger A pointer to a Loggerobject
bool TalkFileCreator::createTalkFiles()
{
    m_abort = false;
    QString errStr;

    emit logItem(tr("Starting Talk file generation for folder %1")
            .arg(m_dir), LOGINFO);
    emit logProgress(0,0);
    QCoreApplication::processEvents();

    // read in Maps of paths - file/dirnames
    emit logItem(tr("Reading Filelist..."),LOGINFO);
    if(createTalkList(m_mountpoint + "/" + m_dir) == false)
    {
        emit logItem(tr("Talk file creation aborted"),LOGERROR);
        doAbort();
        return false;
    }
    QCoreApplication::processEvents();

    // generate entries
    TalkGenerator generator(this);
    // no string corrections yet: do not set language for TalkGenerator.
    connect(&generator, &TalkGenerator::done, this, &TalkFileCreator::done);
    connect(&generator, &TalkGenerator::logItem, this, &TalkFileCreator::logItem);
    connect(&generator, &TalkGenerator::logProgress, this, &TalkFileCreator::logProgress);
    connect(this, &TalkFileCreator::aborted, &generator, &TalkGenerator::abort);

    if(generator.process(&m_talkList) == TalkGenerator::eERROR)
    {
        doAbort();
        return false;
    }

    // Copying talk files
    emit logItem(tr("Copying Talkfiles..."),LOGINFO);
    if(copyTalkFiles(&errStr) == false)
    {
        emit logItem(errStr,LOGERROR);
        doAbort();
        return false;
    }

    // Deleting left overs
    if( !cleanup())
        return false;

    emit logItem(tr("Finished creating Talk files"),LOGOK);
    emit logProgress(1,1);
    emit done(false);

    return true;
}

//! \brief Strips everything after and including the last dot in a string. If there is no dot, nothing is changed
//!
//! \param filename The filename from which to strip the Extension
//! \returns the modified string
QString TalkFileCreator::stripExtension(QString filename)
{
    // only strip extension if there is a dot in the filename and there are chars before the dot
    if(filename.lastIndexOf(".") != -1 && filename.left(filename.lastIndexOf(".")) != "")
        return filename.left(filename.lastIndexOf("."));
    else
        return filename;
}

//! \brief Does needed Tasks when we need to abort. Cleans up Files. Stops the Logger, Stops TTS and Encoder
//!
void TalkFileCreator::doAbort()
{
    cleanup();
    emit logProgress(0,1);
    emit done(true);
}
//! \brief creates a list of what to generate
//!
//! \param startDir The directory from which to start scanning
bool TalkFileCreator::createTalkList(QDir startDir)
{
    LOG_INFO() << "generating list of files" << startDir;
    m_talkList.clear();

     // create Iterator
    QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags;
    if(m_recursive)
        flags = QDirIterator::Subdirectories;

    QDirIterator it(startDir,flags);

    //create temp directory
    QDir tempDir(QDir::tempPath()+ "/talkfiles/");
    if(!tempDir.exists())
        tempDir.mkpath(QDir::tempPath()+ "/talkfiles/");

    // read in Maps of paths - file/dirnames
    while (it.hasNext())
    {
        it.next();
        if(m_abort)
        {
            return false;
        }

        QFileInfo fileInf = it.fileInfo();

        // its a dir
        if(fileInf.isDir())
        {
            QDir dir = fileInf.dir();

            // insert into List
            if(!dir.dirName().isEmpty() && m_talkFolders)
            {
                // check if we should ignore it
                if(QFileInfo::exists(dir.path() + "/talkclips.ignore"))
                {
                    continue;
                }

                // check to see if it's already covered
                if(m_generateOnlyNew && QFileInfo::exists(dir.path() + "/_dirname.talk"))
                {
                    continue;
                }

                //generate entry
                TalkGenerator::TalkEntry entry;
                entry.toSpeak = dir.dirName();
                entry.wavfilename = QDir::tempPath() + "/talkfiles/"
                    + QCryptographicHash::hash(entry.toSpeak.toUtf8(),
                    QCryptographicHash::Md5).toHex() + ".wav";
                entry.talkfilename = QDir::tempPath() + "/talkfiles/"
                    + QCryptographicHash::hash(entry.toSpeak.toUtf8(),
                    QCryptographicHash::Md5).toHex() + ".talk";
                entry.target = dir.path() + "/_dirname.talk";
                entry.voiced = false;
                entry.encoded = false;
                LOG_INFO() << "toSpeak:" << entry.toSpeak
                           << "target:" << entry.target
                           << "intermediates:" << entry.wavfilename << entry.talkfilename;
                m_talkList.append(entry);
            }
        }
        else  // its a File
        {
            // insert into List
            if(!fileInf.fileName().isEmpty()
                    && !fileInf.fileName().endsWith(".talk")
                    && m_talkFiles)
            {
                //test if we should ignore this file
                bool match = false;
                for(int i=0; i < m_ignoreFiles.size();i++)
                {
                    QString pattern = m_ignoreFiles[i].trimmed()
                                        .replace("?", ".").replace("*", ".*");
                    QRegularExpression rx(pattern);
                    if(rx.match(fileInf.fileName()).hasMatch())
                        match = true;

                }
                if(match)
                    continue;

                // check if we should ignore it
                if(m_generateOnlyNew && QFileInfo::exists(fileInf.path() + "/" + fileInf.fileName() + ".talk"))
                {
                    continue;
                }

                //generate entry
                TalkGenerator::TalkEntry entry;
                if(m_stripExtensions)
                    entry.toSpeak = stripExtension(fileInf.fileName());
                else
                    entry.toSpeak = fileInf.fileName();
                entry.wavfilename = QDir::tempPath() + "/talkfiles/"
                    + QCryptographicHash::hash(entry.toSpeak.toUtf8(),
                    QCryptographicHash::Md5).toHex() + ".wav";
                entry.talkfilename = QDir::tempPath() + "/talkfiles/"
                    + QCryptographicHash::hash(entry.toSpeak.toUtf8(),
                    QCryptographicHash::Md5).toHex() + ".talk";
                entry.target =  fileInf.path() + "/" + fileInf.fileName() + ".talk";
                entry.voiced = false;
                entry.encoded = false;
                LOG_INFO() << "toSpeak:" << entry.toSpeak
                           << "target:" << entry.target
                           << "intermediates:"
                           << entry.wavfilename << entry.talkfilename;
                m_talkList.append(entry);
            }
        }
        QCoreApplication::processEvents();
    }
    LOG_INFO() << "list created, entries:" << m_talkList.size();
    return true;
}


//! \brief copys Talkfiles from the temp dir to the target. Progress and installlog is handled inside
//!
//! \param errString Pointer to a QString where the error cause is written.
//! \returns true on success, false on error or user abort
bool TalkFileCreator::copyTalkFiles(QString* errString)
{
    int progressMax = m_talkList.size();
    int m_progress = 0;
    emit logProgress(m_progress,progressMax);

    QSettings installlog(m_mountpoint + "/.rockbox/rbutil.log", QSettings::IniFormat, nullptr);
    installlog.beginGroup("talkfiles");

    for(int i=0; i < m_talkList.size(); i++)
    {
        if(m_abort)
        {
            *errString = tr("File copy aborted");
            return false;
        }

        // skip not encoded files
        if(m_talkList[i].encoded == false)
        {
            emit logProgress(++m_progress,progressMax);
            continue; // this file was skipped in one of the previous steps
        }
        // remove target if it exists, and if we should overwrite it
        if(QFile::exists(m_talkList[i].target))
            QFile::remove(m_talkList[i].target);

        // copying
        LOG_INFO() << "copying" << m_talkList[i].talkfilename
                   << "to" << m_talkList[i].target;
        if(!QFile::copy(m_talkList[i].talkfilename, m_talkList[i].target))
        {
            *errString = tr("Copying of %1 to %2 failed")
                    .arg(m_talkList[i].talkfilename, m_talkList[i].target);
            return false;
        }

        // add to installlog
        QString now = QDate::currentDate().toString("yyyyMMdd");
        installlog.setValue(m_talkList[i].target.remove(0,m_mountpoint.length()),now);

        emit logProgress(++m_progress,progressMax);
        QCoreApplication::processEvents();
    }
    installlog.endGroup();
    installlog.sync();
    return true;
}


//! \brief Cleans up Files potentially left in the temp dir
//!
bool TalkFileCreator::cleanup()
{
    emit logItem(tr("Cleaning up..."),LOGINFO);

    for(int i=0; i < m_talkList.size(); i++)
    {
        if(QFile::exists(m_talkList[i].wavfilename))
                QFile::remove(m_talkList[i].wavfilename);
        if(QFile::exists(m_talkList[i].talkfilename))
                QFile::remove(m_talkList[i].talkfilename);

        QCoreApplication::processEvents();
    }
    emit logItem(tr("Finished"),LOGINFO);
    return true;
}

//! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position
//!
void TalkFileCreator::abort()
{
    m_abort = true;
    emit aborted();
}