File indexing completed on 2024-04-28 16:06:19
0001 /* AUDEX CDDA EXTRACTOR 0002 * SPDX-FileCopyrightText: Copyright (C) 2007 Marco Nelles 0003 * <https://userbase.kde.org/Audex> 0004 * 0005 * SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 #ifndef PLACEHOLDERPARSER_H 0009 #define PLACEHOLDERPARSER_H 0010 0011 #include <QDate> 0012 #include <QDateTime> 0013 #include <QDesktopServices> 0014 #include <QDialog> 0015 #include <QDir> 0016 #include <QFileInfo> 0017 #include <QImage> 0018 #include <QImageReader> 0019 #include <QLocale> 0020 #include <QMetaType> 0021 #include <QObject> 0022 #include <QTemporaryFile> 0023 0024 #include <KLocalizedString> 0025 0026 #include "config.h" 0027 #include "utils/parameters.h" 0028 0029 #define VAR_ALBUM_ARTIST "artist" 0030 #define VAR_ALBUM_TITLE "title" 0031 #define VAR_TRACK_ARTIST "tartist" 0032 #define VAR_TRACK_TITLE "ttitle" 0033 #define VAR_TRACK_NO "trackno" 0034 #define VAR_CD_NO "cdno" 0035 #define VAR_DATE "date" 0036 #define VAR_GENRE "genre" 0037 #define VAR_ISRC "isrc" 0038 #define VAR_SUFFIX "suffix" 0039 #define VAR_ENCODER "encoder" 0040 0041 #define VAR_INPUT_FILE "i" 0042 #define VAR_OUTPUT_FILE "o" 0043 #define VAR_COVER_FILE "cover" 0044 0045 #define VAR_MCN "mcn" 0046 #define VAR_DISCID "discid" 0047 #define VAR_CD_SIZE "size" 0048 #define VAR_CD_LENGTH "length" 0049 #define VAR_TODAY "today" 0050 #define VAR_NOW "now" 0051 #define VAR_LINEBREAK "br" 0052 0053 #define VAR_AUDEX "audex" 0054 #define VAR_NO_OF_TRACKS "nooftracks" 0055 0056 #define STANDARD_EMBED_COVER_FORMAT "jpeg" 0057 #define STANDARD_EMBED_COVER_WIDTH 600 0058 0059 typedef QMap<QString, QVariant> Placeholders; 0060 typedef QMap<QString, Parameters> PlaceholdersParameters; 0061 0062 class SchemeParser : public QObject 0063 { 0064 Q_OBJECT 0065 public: 0066 explicit SchemeParser(QObject *parent = nullptr); 0067 ~SchemeParser() override; 0068 0069 // placeholders_parameters: return the actually found placeholders with their parameters as QMap 0070 const QString parseScheme(const QString &scheme, const Placeholders &placeholders, PlaceholdersParameters *placeholders_parameters = nullptr); 0071 0072 const QString parsePerTrackFilenameScheme(const QString &scheme, 0073 const int trackno, 0074 const int cdno, 0075 const int trackoffset, 0076 const int nooftracks, 0077 const QString &artist, 0078 const QString &title, 0079 const QString &tartist, 0080 const QString &ttitle, 0081 const QString &date, 0082 const QString &genre, 0083 const QString &isrc, 0084 const QString &suffix, 0085 const bool fat32compatible, 0086 const bool replacespaceswithunderscores, 0087 const bool twodigitstracknum); 0088 0089 const QString parsePerTrackCommandScheme(const QString &scheme, 0090 const QString &input, 0091 const QString &output, 0092 const int trackno, 0093 const int cdno, 0094 const int trackoffset, 0095 const int nooftracks, 0096 const QString &artist, 0097 const QString &title, 0098 const QString &tartist, 0099 const QString &ttitle, 0100 const QString &date, 0101 const QString &genre, 0102 const QString &isrc, 0103 const QString &suffix, 0104 const QImage &cover, 0105 const QString &tmppath, 0106 const QString &encoder, 0107 const bool demomode = false); 0108 0109 const QString parseFilenameScheme(const QString &scheme, 0110 const int cdno, 0111 const int nooftracks, 0112 const QString &artist, 0113 const QString &title, 0114 const QString &date, 0115 const QString &genre, 0116 const QString &suffix, 0117 const bool fat32compatible); 0118 0119 void parseInfoTextScheme(QStringList &text, 0120 const QString &artist, 0121 const QString &title, 0122 const QString &date, 0123 const QString &genre, 0124 const QString &mcn, 0125 const quint32 discid, 0126 const qreal size, 0127 const int length, 0128 const int nooftracks); 0129 0130 inline bool error() const 0131 { 0132 return !p_error_string.isEmpty(); 0133 } 0134 0135 inline const QString errorString() const 0136 { 0137 return p_error_string; 0138 } 0139 0140 // scheme: 1 == PerTrackFilename, 2 = PerTrackCommand, 3 == Filename, 4 == InfoText 0141 static const QString helpHTMLDoc(const int scheme) 0142 { 0143 QString result = 0144 "<html>" 0145 "<head>" 0146 "<style type=\"text/css\">" 0147 "* { font-size: 0.8em; }" 0148 "table { margin: 8px 0 8px; }" 0149 "table tr th { padding: 4px 6px; border-bottom: 1px solid; }" 0150 "table tr td { padding: 2px 2px; border-bottom: 1px dotted; }" 0151 "</style>" 0152 "</head>" 0153 "<body>"; 0154 0155 result.append( 0156 i18n("<p>The following placeholders will be replaced with their particular meaning:</p>" 0157 "<table>" 0158 "<tr><th>Placeholder</th><th>Description</th></tr>" 0159 "<tr><td><tt>$artist</tt></td><td>The artist of the CD. If your CD is a compilation then this tag represents the title in most " 0160 "cases.</td></tr>" 0161 "<tr><td><tt>$title</tt></td><td>The title of the CD. If your CD is a compilation then this tag represents the subtitle in most " 0162 "cases.</td></tr>" 0163 "<tr><td><tt>$date</tt></td><td>The release date of the CD. In almost all cases this is the year.</td></tr>" 0164 "<tr><td><tt>$genre</tt></td><td>The genre of the CD.</td></tr>" 0165 "<tr><td><tt>$cdno</tt></td><td>The CD number of a multi-CD album. Often compilations consist of several CDs. <i>Note:</i> If the " 0166 "multi-CD flag is <b>not</b> set for the current CD then this value will be empty.</td></tr>" 0167 "<tr><td><tt>$nooftracks</tt></td><td>The total number of audio tracks of the CD.</td></tr>" 0168 "<tr><td><tt>$encoder</tt></td><td>Encoder name and version.</td></tr>" 0169 "<tr><td><tt>$audex</tt></td><td>Audex name and version.</td></tr>" 0170 "</table>")); 0171 0172 result.append(i18n( 0173 "<p>Placeholders in Audex can have parameters in the form key=value. E.g. <tt>${title lowercase=true}</tt>. In this example " 0174 "the title will be lowercased. The following general parameters can be used with placeholders:</p>" 0175 "<table>" 0176 "<tr><th>Key</th><th>Value</th><th>Description</th></tr>" 0177 "<tr><td><tt>lowercase</tt></td><td>true/false</td><td>The placeholder value will be lowercased.</td></tr>" 0178 "<tr><td><tt>uppercase</tt></td><td>true/false</td><td>The placeholder value will be uppercased.</td></tr>" 0179 "<tr><td><tt>underscores</tt></td><td>true/false</td><td>Replace the spaces of the placeholder value with underscores.</td></tr>" 0180 "<tr><td><tt>fat32compatible</tt></td><td>true/false</td><td>Replace illegal filename characters of a FAT32 filesystem with underscores.</td></tr>" 0181 "<tr><td><tt>replace_chars</tt></td><td>true/false</td><td>Replace characters. This parameter needs two additional keys of the same value size:" 0182 "<tt>replace_char_list_from</tt>, <tt>replace_char_list_to</tt>. These are lists of characters. The first character of" 0183 "<tt>replace_char_list_from</tt> will be replaced by the first character of <tt>replace_char_list_to</tt> and so on.</td></tr>" 0184 "<tr><td><tt>left</tt></td><td>Number</td><td>Take nth characters from the left of the placeholder value.</td></tr>" 0185 "<tr><td><tt>length</tt></td><td>Number</td><td>If the placeholder value is a number expand it to the given length. Furthermore you can define " 0186 "a fill character with the additional key <tt>fillchar</tt>. Default fillchar is '0'.</td></tr>" 0187 "<tr><td><tt>pre</tt></td><td>String</td><td>A string which will be placed <b>before</b> the value. Especially useful for command line parameters " 0188 "which should not be set at all if the value is empty.</td></tr>" 0189 "<tr><td><tt>post</tt></td><td>String</td><td>A string which will be placed <b>after</b> the value.</td></tr>" 0190 "</table>")); 0191 0192 if (scheme == 1 || scheme == 2) { 0193 result.append( 0194 i18n("<table>" 0195 "<tr><th>Placeholder</th><th>Description</th></tr>" 0196 "<tr><td>$tartist</td><td>This is the artist of every track. It is especially useful on compilation CDs.</td></tr>" 0197 "<tr><td>$ttitle</td><td>The track title. Normally each track on a CD has its own title, which is the name of the song.</td></tr>" 0198 "<tr><td>$trackno</td><td>The track number. First track is 1.</td></tr>" 0199 "<tr><td><tt>$isrc</tt></td><td>The International Standard Recording Code (ISRC) of the track (only available if supported by your " 0200 "device).</td></tr>" 0201 "</table>")); 0202 } 0203 0204 if (scheme == 2) { 0205 result.append( 0206 i18n("<table>" 0207 "<tr><th>Placeholder</th><th>Specific parameter</th><th>Description</th></tr>" 0208 "<tr><td><tt>$i</tt></td><td></td><td>The temporary WAVE file (RIFF WAVE) created by Audex from CD audio track. This is the " 0209 "input file for your command line encoder.</td></tr>" 0210 "<tr><td><tt>$o</tt></td><td></td><td>The full output filename and path. Use it as the output for your command line encoder.</td></tr>" 0211 "<tr><td><tt>$cover</tt></td><td><tt>format,x,y</tt></td><td>Filename of the cover file. If no cover is set, this will be empty. Mostly " 0212 "useful in conjunction with the <tt>pre</tt> parameter. Image can be scaled with the <tt>x</tt> and <tt>y</tt> parameters. Possible image " 0213 "<tt>formats</tt> are JPEG, PNG, GIF or BMP (Default: JPEG). <i><b>Note:</b> " 0214 "LAME discards cover files larger than 128 KiB.</i></td></tr>" 0215 "</table>")); 0216 } 0217 0218 if (scheme == 4) { 0219 result.append(i18n( 0220 "<table>" 0221 "<tr><th>Placeholder</th><th>Specific parameter</th><th>Description</th></tr>" 0222 "<tr><td>$size</td><td><tt>iec,precision</tt></td><td>Prints the overall size of all extracted (encoded) music files (incl. the cover image " 0223 "file). With <tt>iec</tt> calculate (k)ibi, (m)ebi or (g)ibi. The additional parameter <tt>precision</tt> can define the number " 0224 "of decimal places.</td></tr>" 0225 "<tr><td>$length</td><td></td><td>Prints the relevant overall length of all extracted tracks. The format is min:sec.</td></tr>" 0226 "<tr><td>$nooftracks</td><td></td><td>Prints the total number of extracted tracks.</td></tr>" 0227 "<tr><td>$discid</td><td>base</td><td>Prints the CDDB discid in hexadecimal format.</td></tr>" 0228 "<tr><td><tt>$mcn</tt></td><td></td><td>The Media Catalog Number (MCN) of the CD (only available if supported by your device).</td></tr>" 0229 "<tr><td>$now</td><td><tt>format,locale</tt></td><td>Prints the current date and/or time. The parameter format specifies the output. " 0230 "Please consult official qt documentation (<tt>https://doc.qt.io/qt-5/qtime.html#toString</tt>, " 0231 "<tt>https://doc.qt.io/qt-6/qdate.html#toString</tt>) for the supported specifiers within the format string. With the additional key " 0232 "<tt>locale</tt> you can specify a language setting. By default your " 0233 "system locales are used. The locale has the format <tt>language_TERRITORY</tt>, e.g. <tt>en_EN</tt>. <tt>language</tt> is a lowercase, " 0234 "two-letter, ISO 639 language code and <tt>TERRITORY</tt> an uppercase, two-letter, ISO 3166 territory code.</td></tr>" 0235 "<tr><td>$br</td><td></td><td>Prints a linebreak.</td></tr>" 0236 "</table>")); 0237 } 0238 0239 result.append( 0240 "</body>" 0241 "</html>"); 0242 0243 return result; 0244 } 0245 0246 Q_SIGNALS: 0247 void error(const QString &message, const QString &details = QString()); 0248 0249 private: 0250 const Parameters parse_keyvalue_stringlist(const QStringList &keyvaluepairs); 0251 0252 QString p_error_string; 0253 0254 inline const QString 0255 customize_placeholder_value(const QString &string, bool fat32compatible = false, bool compatible2 = true, bool replacespaceswithunderscores = false) 0256 { 0257 QString tmp = string; 0258 if (fat32compatible) 0259 tmp = make_fat32_compatible(tmp); 0260 else if (compatible2) 0261 tmp = make_compatible_2(tmp); 0262 else 0263 tmp = make_compatible(tmp); 0264 if (replacespaceswithunderscores) 0265 tmp = replace_spaces_with_underscores(tmp); 0266 return tmp; 0267 } 0268 0269 const QString make_compatible(const QString &string); 0270 const QString make_compatible_2(const QString &string); 0271 const QString make_fat32_compatible(const QString &string); 0272 const QString replace_spaces_with_underscores(const QString &string); 0273 const QString replace_char_list(const QString &from, const QString &to, const QString &string); 0274 }; 0275 0276 #endif