File indexing completed on 2024-12-22 04:40:09

0001 /*
0002     SPDX-FileCopyrightText: 2021-2022 Mladen Milinkovic <max@smoothware.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "webvttoutputformat.h"
0008 
0009 #include "core/richtext/richdocument.h"
0010 #include "core/subtitleiterator.h"
0011 #include "helpers/common.h"
0012 
0013 #include <QRegularExpression>
0014 
0015 using namespace SubtitleComposer;
0016 
0017 
0018 WebVTTOutputFormat::WebVTTOutputFormat()
0019     : OutputFormat($("WebVTT"), QStringList($("vtt")))
0020 {}
0021 
0022 inline static QString
0023 fixEmptyLines(QString str)
0024 {
0025     staticRE$(reEmptyLine, "\\n(?=\\n)", REu);
0026     return str.replace(reEmptyLine, $("\n "));
0027 }
0028 
0029 QString
0030 WebVTTOutputFormat::dumpSubtitles(const Subtitle &subtitle, bool primary) const
0031 {
0032     QString ret;
0033 
0034     ret += $("WEBVTT");
0035     ret.append(QChar::LineFeed);
0036     const QString &intro = fixEmptyLines(subtitle.meta("comment.intro.0"));
0037     if(!intro.isEmpty()) {
0038         ret.append(intro);
0039         ret.append(QChar::LineFeed);
0040     }
0041     ret.append(QChar::LineFeed);
0042 
0043     for(int noteId = 0;;) {
0044         const QByteArray key(QByteArray("comment.top.") + QByteArray::number(noteId++));
0045         if(!subtitle.metaExists(key))
0046             break;
0047         ret.append($("NOTE"));
0048         ret.append(QChar::LineFeed);
0049         ret.append(fixEmptyLines(subtitle.meta(key)));
0050         ret.append(QChar::LineFeed);
0051         ret.append(QChar::LineFeed);
0052     }
0053 
0054     if(!subtitle.stylesheet()->unformattedCSS().isEmpty()) {
0055         ret.append($("STYLE"));
0056         ret.append(QChar::LineFeed);
0057         ret.append(fixEmptyLines(subtitle.stylesheet()->unformattedCSS()));
0058         ret.append(QChar::LineFeed);
0059         ret.append(QChar::LineFeed);
0060     }
0061 
0062     for(SubtitleIterator it(subtitle); it.current(); ++it) {
0063         const SubtitleLine *line = it.current();
0064 
0065         const QString &comment = line->meta("comment");
0066         if(!comment.isEmpty()) {
0067             ret.append($("NOTE"));
0068             ret.append(comment.contains(QChar::LineFeed) ? QChar::LineFeed : QChar::Space);
0069             ret.append(fixEmptyLines(comment));
0070             ret.append(QChar::LineFeed);
0071             ret.append(QChar::LineFeed);
0072         }
0073 
0074         const QString &cueId = line->meta("id");
0075         if(!cueId.isEmpty()) {
0076             ret.append(cueId);
0077             ret.append(QChar::LineFeed);
0078         }
0079 
0080         const Time showTime = line->showTime();
0081         const Time hideTime = line->hideTime();
0082         ret += QString::asprintf("%02d:%02d:%02d.%03d --> %02d:%02d:%02d.%03d",
0083                     showTime.hours(), showTime.minutes(), showTime.seconds(), showTime.millis(),
0084                     hideTime.hours(), hideTime.minutes(), hideTime.seconds(), hideTime.millis());
0085         const SubtitleRect &p = line->pos();
0086         // FIXME: consider hAlign/vAlign in rect calculations
0087         // FIXME: position/line can have extra alignment/anchor parameter
0088         if(p.vertical) {
0089             ret.append($(" vertical:lr")); // FIXME: RTL support (vertical:rl)
0090             const int top = p.top;
0091             const int left = p.left;
0092             const int height = int(p.bottom) - top;
0093             if(left) // FIXME: with vertical:rl should be right
0094                 ret.append(QString::asprintf(" line:%02d%%", left));
0095             if(top)
0096                 ret.append(QString::asprintf(" position:%02d%%", top));
0097             if(height != 100)
0098                 ret.append(QString::asprintf(" size:%02d%%", height));
0099         } else {
0100             const int top = p.top;
0101             const int left = p.left;
0102             const int width = int(p.right) - left;
0103             if(top)
0104                 ret.append(QString::asprintf(" line:%02d%%", top));
0105             if(left)
0106                 ret.append(QString::asprintf(" position:%02d%%", left));
0107             if(width != 100)
0108                 ret.append(QString::asprintf(" size:%02d%%", width));
0109         }
0110         if(p.hAlign == SubtitleRect::START)
0111             ret.append(QLatin1String(" align:start"));
0112         else if(p.hAlign == SubtitleRect::END)
0113             ret.append(QLatin1String(" align:end"));
0114         ret.append(QChar::LineFeed);
0115 
0116         const RichString text = (primary ? line->primaryDoc() : line->secondaryDoc())->toRichText();
0117         ret += text.richString()
0118                 .replace(QLatin1String("&amp;"), QLatin1String("&"))
0119                 .replace(QLatin1String("&lt;"), QLatin1String("<"))
0120                 .replace(QLatin1String("&gt;"), QLatin1String(">"));
0121 
0122         ret += $("\n\n");
0123     }
0124     return ret;
0125 }