File indexing completed on 2024-05-19 04:55:59

0001 /**
0002  * \file textimporter.cpp
0003  * Import tags from text.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 19 Jun 2011
0008  *
0009  * Copyright (C) 2011-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "textimporter.h"
0028 #include "importparser.h"
0029 #include "trackdatamodel.h"
0030 
0031 /**
0032  * Constructor.
0033  *
0034  * @param trackDataModel track data to be filled with imported values
0035  */
0036 TextImporter::TextImporter(TrackDataModel* trackDataModel)
0037   : m_headerParser(new ImportParser),
0038     m_trackParser(new ImportParser),
0039     m_trackDataModel(trackDataModel)
0040 {
0041 }
0042 
0043 /**
0044  * Destructor.
0045  */
0046 TextImporter::~TextImporter()
0047 {
0048   // Must not be inline because of forwared declared QScopedPointer.
0049 }
0050 
0051 /**
0052  * Look for album specific information (artist, album, year, genre) in
0053  * a header.
0054  *
0055  * @param frames frames to put resulting values in,
0056  *           fields which are not found are not touched.
0057  *
0058  * @return true if one or more field were found.
0059  */
0060 bool TextImporter::parseHeader(TrackData& frames)
0061 {
0062   int pos = 0;
0063   m_headerParser->setFormat(m_headerFormat);
0064   return m_headerParser->getNextTags(m_text, frames, pos);
0065 }
0066 
0067 /**
0068  * Update track data list with imported tags.
0069  *
0070  * @param text text to import
0071  * @param headerFormat header format
0072  * @param trackFormat track format
0073  *
0074  * @return true if tags were found.
0075  */
0076 bool TextImporter::updateTrackData(
0077   const QString& text,
0078   const QString& headerFormat, const QString& trackFormat) {
0079   m_text = text;
0080   m_headerFormat = headerFormat;
0081   m_trackFormat = trackFormat;
0082 
0083   TrackData framesHdr;
0084   (void)parseHeader(framesHdr);
0085 
0086   TrackData frames(framesHdr);
0087   bool start = true;
0088   ImportTrackDataVector trackDataVector(m_trackDataModel->getTrackData());
0089   auto it = trackDataVector.begin();
0090   bool atTrackDataListEnd = it == trackDataVector.end();
0091   while (getNextTags(frames, start)) {
0092     start = false;
0093     if (atTrackDataListEnd) {
0094       ImportTrackData trackData;
0095       trackData.setFrameCollection(frames);
0096       trackDataVector.push_back(trackData);
0097     } else {
0098       while (!atTrackDataListEnd && !it->isEnabled()) {
0099         ++it;
0100         atTrackDataListEnd = it == trackDataVector.end();
0101       }
0102       if (!atTrackDataListEnd) {
0103         it->setFrameCollection(frames);
0104         ++it;
0105         atTrackDataListEnd = it == trackDataVector.end();
0106       }
0107     }
0108     frames = framesHdr;
0109   }
0110   frames.clear();
0111   while (!atTrackDataListEnd) {
0112     if (it->isEnabled()) {
0113       if (it->getFileDuration() == 0) {
0114         it = trackDataVector.erase(it);
0115       } else {
0116         it->setFrameCollection(frames);
0117         it->setImportDuration(0);
0118         ++it;
0119       }
0120     } else {
0121       ++it;
0122     }
0123     atTrackDataListEnd = it == trackDataVector.end();
0124   }
0125 
0126   if (!start) {
0127     /* start is false => tags were found */
0128     if (QList<int> trackDuration = getTrackDurations();
0129         !trackDuration.isEmpty()) {
0130       it = trackDataVector.begin();
0131       for (auto tdit = trackDuration.constBegin();
0132            tdit != trackDuration.constEnd();
0133            ++tdit) {
0134         if (it != trackDataVector.end()) {
0135           if (it->isEnabled()) {
0136             it->setImportDuration(*tdit);
0137           }
0138           ++it;
0139         } else {
0140           break;
0141         }
0142       }
0143     }
0144     m_trackDataModel->setTrackData(trackDataVector);
0145     return true;
0146   }
0147   return false;
0148 }
0149 
0150 /**
0151  * Get next line as frames from imported file or clipboard.
0152  *
0153  * @param frames frames
0154  * @param start true to start with the first line, false for all
0155  *              other lines
0156  *
0157  * @return true if ok (result in st),
0158  *         false if end of file reached.
0159  */
0160 bool TextImporter::getNextTags(TrackData& frames, bool start)
0161 {
0162   static int pos = 0;
0163   if (start || pos == 0) {
0164     pos = 0;
0165     m_trackParser->setFormat(m_trackFormat, true);
0166   }
0167   return m_trackParser->getNextTags(m_text, frames, pos);
0168 }
0169 
0170 /**
0171  * Get list with track durations.
0172  *
0173  * @return list with track durations,
0174  *         empty if no track durations found.
0175  */
0176 QList<int> TextImporter::getTrackDurations() const
0177 {
0178   QList<int> lst;
0179   if (m_headerParser) {
0180     lst = m_headerParser->getTrackDurations();
0181   }
0182   if (lst.isEmpty() && m_trackParser) {
0183     lst = m_trackParser->getTrackDurations();
0184   }
0185   return lst;
0186 }
0187 
0188 /**
0189  * Import text from tags to other tags.
0190  *
0191  * @param sourceFormat format to create source text
0192  * @param extractionFormat regular expression to extract other tags
0193  * @param trackDataVector track data to process
0194  */
0195 void TextImporter::importFromTags(
0196   const QString& sourceFormat,
0197   const QString& extractionFormat,
0198   ImportTrackDataVector& trackDataVector)
0199 {
0200   ImportParser parser;
0201   parser.setFormat(extractionFormat);
0202   for (auto it = trackDataVector.begin(); it != trackDataVector.end(); ++it) {
0203     if (it->isEnabled()) {
0204       QString text(it->formatString(sourceFormat));
0205       int pos = 0;
0206       parser.getNextTags(text, *it, pos);
0207     }
0208   }
0209 }
0210 
0211 /**
0212  * Import text from tags to other tags.
0213  *
0214  * @param sourceFormat format to create source text
0215  * @param parser import parser which is initialized with extraction format
0216  * @param trackData track data to process
0217  */
0218 void TextImporter::importFromTags(
0219     const QString& sourceFormat, ImportParser& parser, TrackData& trackData)
0220 {
0221   QString text(trackData.formatString(sourceFormat));
0222   int pos = 0;
0223   parser.getNextTags(text, trackData, pos);
0224 }