Drop Qt dependency when building only CLI
This commit is contained in:
parent
cd301090c2
commit
aaccbcc375
|
@ -2,31 +2,37 @@ cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
|||
|
||||
# meta data
|
||||
set(META_PROJECT_NAME tageditor)
|
||||
set(META_PROJECT_TYPE application)
|
||||
set(META_APP_NAME "Tag Editor")
|
||||
set(META_APP_CATEGORIES "Utility;Audio;Video;")
|
||||
set(META_APP_AUTHOR "Martchus")
|
||||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||
set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska.")
|
||||
set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska")
|
||||
set(META_VERSION_MAJOR 1)
|
||||
set(META_VERSION_MINOR 4)
|
||||
set(META_VERSION_PATCH 1)
|
||||
|
||||
# add project files
|
||||
set(HEADER_FILES
|
||||
application/knownfieldmodel.h
|
||||
application/targetlevelmodel.h
|
||||
application/main.h
|
||||
application/settings.h
|
||||
cli/mainfeatures.h
|
||||
application/knownfieldmodel.h
|
||||
)
|
||||
set(SRC_FILES
|
||||
application/main.cpp
|
||||
cli/mainfeatures.cpp
|
||||
application/knownfieldmodel.cpp
|
||||
)
|
||||
|
||||
set(GUI_HEADER_FILES
|
||||
application/targetlevelmodel.h
|
||||
application/settings.h
|
||||
misc/htmlinfo.h
|
||||
misc/utility.h
|
||||
)
|
||||
set(SRC_FILES
|
||||
application/knownfieldmodel.cpp
|
||||
set(GUI_SRC_FILES
|
||||
application/targetlevelmodel.cpp
|
||||
application/main.cpp
|
||||
application/settings.cpp
|
||||
cli/mainfeatures.cpp
|
||||
misc/htmlinfo.cpp
|
||||
misc/utility.cpp
|
||||
)
|
||||
|
@ -180,8 +186,10 @@ find_package(c++utilities 4.0.0 REQUIRED)
|
|||
use_cpp_utilities()
|
||||
|
||||
# find qtutilities
|
||||
find_package(qtutilities 4.0.0 REQUIRED)
|
||||
use_qt_utilities()
|
||||
if(WIDGETS_GUI OR QUICK_GUI)
|
||||
find_package(qtutilities 5.0.0 REQUIRED)
|
||||
use_qt_utilities()
|
||||
endif()
|
||||
|
||||
# find tagparser
|
||||
find_package(tagparser 6.0.0 REQUIRED)
|
||||
|
@ -192,10 +200,12 @@ list(APPEND ADDITIONAL_QT_MODULES Concurrent Network)
|
|||
|
||||
# include modules to apply configuration
|
||||
include(BasicConfig)
|
||||
include(QtGuiConfig)
|
||||
include(JsProviderConfig)
|
||||
include(WebViewProviderConfig)
|
||||
include(QtConfig)
|
||||
if(WIDGETS_GUI OR QUICK_GUI)
|
||||
include(QtGuiConfig)
|
||||
include(JsProviderConfig)
|
||||
include(WebViewProviderConfig)
|
||||
include(QtConfig)
|
||||
endif()
|
||||
include(WindowsResources)
|
||||
include(AppTarget)
|
||||
include(ShellCompletion)
|
||||
|
|
34
README.md
34
README.md
|
@ -36,7 +36,7 @@ However, it is also possible to force rewriting the entire file.
|
|||
Taking advantage of padding is currently not supported when dealing with Ogg streams (it is supported when
|
||||
dealing with raw FLAC streams).
|
||||
|
||||
## Download / repository
|
||||
## Download / binary repository
|
||||
I currently provide packages for Arch Linux and Windows. For more information checkout my
|
||||
[website](http://martchus.no-ip.biz/website/page.php?name=programming).
|
||||
|
||||
|
@ -71,27 +71,30 @@ you will see a preview with the generated file names.
|
|||
The tag editor also features a MusicBrainz and Cover Art Archive search which can be opened with *F10*. However, this feature is still experimental.
|
||||
|
||||
### CLI
|
||||
Usage:
|
||||
#### Usage
|
||||
```
|
||||
tageditor <operation> [options]
|
||||
```
|
||||
|
||||
Checkout the available operations and options with --help.
|
||||
|
||||
#### Examples
|
||||
Here are some Bash examples which illustrate getting and setting tag information:
|
||||
|
||||
* Displays title, album and artist of all *.m4a files in the specified directory:
|
||||
* *Displays* title, album and artist of all *.m4a files in the specified directory:
|
||||
|
||||
```
|
||||
tageditor get title album artist --files /some/dir/*.m4a
|
||||
```
|
||||
|
||||
* Displays technical information about all *.m4a files in the specified directory:
|
||||
**Note**: All values are printed in UTF-8 encoding, no matter which encoding is actually used within the tag.
|
||||
|
||||
* *Displays* technical information about all *.m4a files in the specified directory:
|
||||
|
||||
```
|
||||
tageditor info --files /some/dir/*.m4a
|
||||
```
|
||||
|
||||
* Sets title, album, artist, cover and track number of all *.m4a files in the specified directory:
|
||||
* *Sets* title, album, artist, cover and track number of all *.m4a files in the specified directory:
|
||||
|
||||
```
|
||||
tageditor set "title=Title of "{1st,2nd,3rd}" file" "title=Title of "{4..16}"th file" \
|
||||
|
@ -103,6 +106,8 @@ Here are some Bash examples which illustrate getting and setting tag information
|
|||
The 16th and following files will all get the name *Title of the 16th file*. The same scheme is used for the track numbers.
|
||||
All files will get the album name *The Album*, the artist *The Artist* and the cover image from the file */path/to/image*.
|
||||
|
||||
**Note**: All specified values are assumed to be UTF-8 encoded, no matter which encoding has been specified as preferred encoding via ``--encoding`` option. (This mentioned option only affects the encoding to be used *within* the tag.)
|
||||
|
||||
* Here is another example, demonstrating the use of arrays and the syntax to auto-increase numeric fields such as the track number:
|
||||
|
||||
```
|
||||
|
@ -124,15 +129,24 @@ Here are some Bash examples which illustrate getting and setting tag information
|
|||
a file has been processed.
|
||||
|
||||
## Build instructions
|
||||
The application depends on c++utilities, qtutilities and tagparser and is built in the same way as these libaries
|
||||
which are also available on my GitHub profile.
|
||||
The application depends on [c++utilities](https://github.com/Martchus/cpp-utilities) and [tagparser](https://github.com/Martchus/tagparser) and is built the same way as these libaries. For basic instructions checkout the README file of [c++utilities](https://github.com/Martchus/cpp-utilities).
|
||||
|
||||
### Building with Qt 5 GUI
|
||||
The following Qt 5 modules are requried: core concurrent gui network declarative/script widgets webenginewidgets/webkitwidgets
|
||||
|
||||
#### Select Qt modules for JavaScript and WebView
|
||||
* If Qt Script is installed on the system, the editor will link against it. Otherwise it will link against Qt QML.
|
||||
* To force usage of Qt Script/Qt QML or to disable both add `-DJS_PROVIDER=script/qml/none` to the cmake arguments.
|
||||
* To force usage of Qt Script/Qt QML or to disable both add `-DJS_PROVIDER=script/qml/none` to the CMake arguments.
|
||||
* If Qt WebKitWidgets is installed on the system, the editor will link against it. Otherwise it will link against Qt WebEngineWidgets.
|
||||
* To force usage of Qt WebKit/Qt WebEngine or to disable both add `-DWEBVIEW_PROVIDER=webkit/webengine/none` to the cmake arguments.
|
||||
* To force usage of Qt WebKit/Qt WebEngine or to disable both add `-DWEBVIEW_PROVIDER=webkit/webengine/none` to the CMake arguments.
|
||||
|
||||
### Building without Qt 5 GUI
|
||||
It is possible to build without the GUI if only the CLI is needed. In this case no Qt dependencies (including qtutilities) are required.
|
||||
|
||||
To build without GUI, add the following parameters to the CMake call:
|
||||
```
|
||||
-DWIDGETS_GUI=OFF -DQUICK_GUI=OFF
|
||||
```
|
||||
|
||||
## TODO
|
||||
- Support more formats (EXIF, PDF metadata, Theora in Ogg, ...).
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
|
||||
#include <tagparser/tag.h>
|
||||
|
||||
using namespace Models;
|
||||
using namespace Media;
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
using namespace Models;
|
||||
#else
|
||||
# define QT_TR_NOOP(x) x
|
||||
#endif
|
||||
|
||||
namespace Settings {
|
||||
|
||||
/*
|
||||
|
@ -47,6 +52,7 @@ const char *KnownFieldModel::fieldName(KnownField field)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
QString KnownFieldModel::translatedFieldName(KnownField field)
|
||||
{
|
||||
return tr(fieldName(field));
|
||||
|
@ -118,5 +124,6 @@ QVariant KnownFieldModel::headerData(int section, Qt::Orientation orientation, i
|
|||
}
|
||||
return QVariant();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#ifndef KNOWNFIELDMODEL_H
|
||||
#define KNOWNFIELDMODEL_H
|
||||
|
||||
#include <qtutilities/models/checklistmodel.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
# include <qtutilities/models/checklistmodel.h>
|
||||
# include <QAbstractListModel>
|
||||
# include <QList>
|
||||
#else
|
||||
# include <c++utilities/application/global.h>
|
||||
# define Q_OBJECT
|
||||
#endif
|
||||
|
||||
namespace Media {
|
||||
DECLARE_ENUM_CLASS(KnownField, unsigned int);
|
||||
|
@ -12,7 +16,10 @@ DECLARE_ENUM_CLASS(KnownField, unsigned int);
|
|||
|
||||
namespace Settings {
|
||||
|
||||
class KnownFieldModel : public Models::ChecklistModel
|
||||
class KnownFieldModel
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
: public Models::ChecklistModel
|
||||
#endif
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -23,6 +30,8 @@ public:
|
|||
};
|
||||
|
||||
static const char *fieldName(Media::KnownField field);
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
static QString translatedFieldName(Media::KnownField field);
|
||||
static Models::ChecklistItem mkItem(Media::KnownField field, Qt::CheckState checkState = Qt::Checked);
|
||||
|
||||
|
@ -31,12 +40,15 @@ public:
|
|||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual QString labelForId(const QVariant &id) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
inline Models::ChecklistItem KnownFieldModel::mkItem(Media::KnownField field, Qt::CheckState checkState)
|
||||
{
|
||||
return Models::ChecklistItem(static_cast<int>(field), translatedFieldName(field), checkState);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "./main.h"
|
||||
#include "./knownfieldmodel.h"
|
||||
|
||||
#include "../cli/mainfeatures.h"
|
||||
#if defined(GUI_QTWIDGETS)
|
||||
# include "../gui/initiate.h"
|
||||
# include "./knownfieldmodel.h"
|
||||
#elif defined(GUI_QTQUICK)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "./mainfeatures.h"
|
||||
|
||||
#include "../application/knownfieldmodel.h"
|
||||
#include "../misc/utility.h"
|
||||
#include "../misc/htmlinfo.h"
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
# include "../misc/utility.h"
|
||||
# include "../misc/htmlinfo.h"
|
||||
#endif
|
||||
|
||||
#include <tagparser/mediafileinfo.h>
|
||||
#include <tagparser/tag.h>
|
||||
|
@ -18,18 +20,24 @@
|
|||
#include <c++utilities/io/catchiofailure.h>
|
||||
#include <c++utilities/misc/memory.h>
|
||||
|
||||
#include <QDir>
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
# include <QDir>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace ApplicationUtilities;
|
||||
using namespace ConversionUtilities;
|
||||
using namespace ChronoUtilities;
|
||||
using namespace EscapeCodes;
|
||||
using namespace Utility;
|
||||
using namespace Settings;
|
||||
using namespace Media;
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
using namespace Utility;
|
||||
#endif
|
||||
|
||||
namespace Cli {
|
||||
|
||||
|
@ -57,7 +65,7 @@ struct FieldDenotation
|
|||
DenotationType type;
|
||||
TagType tagType;
|
||||
TagTarget tagTarget;
|
||||
std::vector<std::pair<unsigned int, QString> > values;
|
||||
vector<pair<unsigned int, string> > values;
|
||||
};
|
||||
|
||||
FieldDenotation::FieldDenotation(KnownField field) :
|
||||
|
@ -71,23 +79,23 @@ inline bool isDigit(char c)
|
|||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
QString incremented(const QString &str, unsigned int toIncrement = 1)
|
||||
string incremented(const string &str, unsigned int toIncrement = 1)
|
||||
{
|
||||
QString res;
|
||||
string res;
|
||||
res.reserve(str.size());
|
||||
unsigned int value = 0;
|
||||
bool hasValue = false;
|
||||
for(const QChar &c : str) {
|
||||
if(toIncrement && c.isDigit()) {
|
||||
value = value * 10 + static_cast<unsigned int>(c.digitValue());
|
||||
for(const char &c : str) {
|
||||
if(toIncrement && c >= '0' && c <= '9') {
|
||||
value = value * 10 + static_cast<unsigned int>(c - '0');
|
||||
hasValue = true;
|
||||
} else {
|
||||
if(hasValue) {
|
||||
res.append(QString::number(value + 1));
|
||||
res += numberToString(value + 1);
|
||||
hasValue = false;
|
||||
--toIncrement;
|
||||
}
|
||||
res.append(c);
|
||||
res += c;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -422,7 +430,7 @@ vector<FieldDenotation> parseFieldDenotations(const Argument &fieldsArg, bool re
|
|||
if(readOnly) {
|
||||
cerr << "Warning: Specified value for \"" << string(fieldDenotationString, fieldNameLen) << "\" will be ignored." << endl;
|
||||
} else {
|
||||
fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, QString::fromLocal8Bit(equationPos + 1)));
|
||||
fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, (equationPos + 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -567,6 +575,7 @@ bool AttachmentInfo::next(AbstractContainer *container)
|
|||
void generateFileInfo(const ArgumentOccurance &, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &validateArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
try {
|
||||
// parse tags
|
||||
MediaFileInfo inputFileInfo(inputFileArg.values().front());
|
||||
|
@ -587,6 +596,12 @@ void generateFileInfo(const ArgumentOccurance &, const Argument &inputFileArg, c
|
|||
::IoUtilities::catchIoFailure();
|
||||
cerr << "Error: An IO failure occured when reading the file \"" << inputFileArg.values().front() << "\"." << endl;
|
||||
}
|
||||
#else
|
||||
VAR_UNUSED(inputFileArg);
|
||||
VAR_UNUSED(outputFileArg);
|
||||
VAR_UNUSED(validateArg);
|
||||
cerr << "Error: Generating HTML info is only available if built with Qt support." << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void printProperty(const char *propName, const char *value, const char *suffix = nullptr, size_t intention = 4)
|
||||
|
@ -804,11 +819,11 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A
|
|||
}
|
||||
// write value
|
||||
try {
|
||||
const auto textValue = tagValueToQString(value);
|
||||
if(textValue.isEmpty()) {
|
||||
const auto textValue = value.toString(TagTextEncoding::Utf8);
|
||||
if(textValue.empty()) {
|
||||
cout << "can't display here (see --extract)";
|
||||
} else {
|
||||
cout << textValue.toLocal8Bit().data();
|
||||
cout << textValue;
|
||||
}
|
||||
} catch(const ConversionException &) {
|
||||
cout << "conversion error";
|
||||
|
@ -832,11 +847,11 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A
|
|||
cout << "none";
|
||||
} else {
|
||||
try {
|
||||
const auto textValue = tagValueToQString(value);
|
||||
if(textValue.isEmpty()) {
|
||||
const auto textValue = value.toString(TagTextEncoding::Utf8);
|
||||
if(textValue.empty()) {
|
||||
cout << "can't display here (see --extract)";
|
||||
} else {
|
||||
cout << textValue.toLocal8Bit().data();
|
||||
cout << textValue;
|
||||
}
|
||||
} catch(const ConversionException &) {
|
||||
cout << "conversion error";
|
||||
|
@ -979,7 +994,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
if((fieldDenotation.tagType == TagType::Unspecified
|
||||
|| (fieldDenotation.tagType | tagType) != TagType::Unspecified)
|
||||
&& (!targetSupported || fieldDenotation.tagTarget == tagTarget)) {
|
||||
pair<unsigned int, QString> *selectedDenotatedValue = nullptr;
|
||||
pair<unsigned int, string> *selectedDenotatedValue = nullptr;
|
||||
for(auto &someDenotatedValue : fieldDenotation.values) {
|
||||
if(someDenotatedValue.first <= fileIndex) {
|
||||
if(!selectedDenotatedValue || (someDenotatedValue.first > selectedDenotatedValue->first)) {
|
||||
|
@ -989,11 +1004,11 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
}
|
||||
if(selectedDenotatedValue) {
|
||||
if(fieldDenotation.type == DenotationType::File) {
|
||||
if(selectedDenotatedValue->second.isEmpty()) {
|
||||
if(selectedDenotatedValue->second.empty()) {
|
||||
tag->setValue(fieldDenotation.field, TagValue());
|
||||
} else {
|
||||
try {
|
||||
MediaFileInfo fileInfo(selectedDenotatedValue->second.toLocal8Bit().constData());
|
||||
MediaFileInfo fileInfo(selectedDenotatedValue->second);
|
||||
fileInfo.open(true);
|
||||
fileInfo.parseContainerFormat();
|
||||
auto buff = make_unique<char []>(fileInfo.size());
|
||||
|
@ -1014,7 +1029,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
if(!tag->canEncodingBeUsed(denotedEncoding)) {
|
||||
usedEncoding = tag->proposedTextEncoding();
|
||||
}
|
||||
tag->setValue(fieldDenotation.field, qstringToTagValue(selectedDenotatedValue->second, usedEncoding));
|
||||
tag->setValue(fieldDenotation.field, TagValue(selectedDenotatedValue->second, TagTextEncoding::Utf8, usedEncoding));
|
||||
if(fieldDenotation.type == DenotationType::Increment && tag == tags.back()) {
|
||||
selectedDenotatedValue->second = incremented(selectedDenotatedValue->second);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <qtutilities/settingsdialog/optioncategory.h>
|
||||
#include <qtutilities/settingsdialog/optioncategorymodel.h>
|
||||
//#include <qtutilities/settingsdialog/qtsettings.h>
|
||||
#include <qtutilities/settingsdialog/qtsettings.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
|
@ -603,7 +603,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
|
|||
category->assignPages(QList<Dialogs::OptionPage *>() << new FileBrowserGeneralOptionPage);
|
||||
categories << category;
|
||||
|
||||
//categories << Dialogs::qtOptionCategory(this);
|
||||
categories << Dialogs::qtOptionCategory(this);
|
||||
|
||||
categoryModel()->setCategories(categories);
|
||||
|
||||
|
|
Loading…
Reference in New Issue