diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac0a5dc5d..5b218b951 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,6 @@ jobs: dbus-1-devel alsa-devel libnotify-devel - protobuf-devel sqlite3-devel libpulse-devel gstreamer-devel @@ -170,8 +169,6 @@ jobs: rsync boost-devel dbus-devel - protobuf-devel - protobuf-compiler sqlite-devel alsa-lib-devel pulseaudio-libs-devel @@ -258,8 +255,6 @@ jobs: glibc-devel boost-devel dbus-devel - protobuf-devel - protobuf-compiler sqlite-devel libasound-devel pulseaudio-devel @@ -360,7 +355,6 @@ jobs: rpmdevtools gettext lib64boost-devel - lib64protobuf-devel lib64sqlite3-devel lib64alsa2-devel lib64pulseaudio-devel @@ -385,7 +379,6 @@ jobs: lib64qt6dbus-devel lib64qt6help-devel lib64qt6test-devel - protobuf-compiler desktop-file-utils appstream-util hicolor-icon-theme @@ -458,8 +451,6 @@ jobs: libglib2.0-dev libdbus-1-dev libboost-dev - libprotobuf-dev - protobuf-compiler libsqlite3-dev libasound2-dev libpulse-dev @@ -539,8 +530,6 @@ jobs: libglib2.0-dev libboost-dev libdbus-1-dev - libprotobuf-dev - protobuf-compiler libsqlite3-dev libasound2-dev libpulse-dev @@ -623,7 +612,6 @@ jobs: libglib2.0-dev libboost-dev libdbus-1-dev - libprotobuf-dev libsqlite3-dev libasound2-dev libpulse-dev @@ -645,7 +633,6 @@ jobs: qt6-l10n-tools gstreamer1.0-alsa gstreamer1.0-pulseaudio - protobuf-compiler - name: Install keyboxd if: matrix.ubuntu_version == 'noble' env: @@ -789,7 +776,7 @@ jobs: - name: Manually Codesign if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-13' working-directory: build - run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libfreetype.6.dylib,libzstd.1.dylib,libutf8_validity.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app + run: codesign -s 383J84DVB6 -f strawberry.app/Contents/Frameworks/{libpcre2-8.0.dylib,libpcre2-16.0.dylib,libpng16.16.dylib,libfreetype.6.dylib,libzstd.1.dylib} strawberry.app/Contents/Frameworks/png.framework/png strawberry.app - name: Manually Codesign if: github.repository == 'strawberrymusicplayer/strawberry' && github.event.pull_request.head.repo.fork == false && matrix.runner == 'macos-14' @@ -1008,7 +995,6 @@ jobs: -DENABLE_LIBMTP=OFF -DENABLE_AUDIOCD=OFF -DENABLE_SPOTIFY=OFF - -DProtobuf_PROTOC_EXECUTABLE="/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc" - name: Run Make run: cmake --build build --config "${{env.cmake_buildtype}}" --parallel $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index afaf99424..b4d23bd32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,13 +120,6 @@ if(NOT Boost_FOUND) find_package(Boost REQUIRED) endif() find_package(ICU COMPONENTS uc i18n REQUIRED) -find_package(Protobuf CONFIG) -if(NOT Protobuf_FOUND) - find_package(Protobuf REQUIRED) -endif() -if(NOT TARGET protobuf::protoc) - message(FATAL_ERROR "Missing Protobuf compiler.") -endif() if(LINUX) find_package(ALSA REQUIRED) pkg_check_modules(DBUS REQUIRED dbus-1) @@ -223,39 +216,19 @@ if(X11_FOUND) endif(X11_FOUND) -option(USE_TAGLIB "Build with TagLib" ON) -option(USE_TAGPARSER "Build with TagParser" OFF) - -# TAGLIB -if(USE_TAGLIB) - find_package(TagLib 2.0) - if(TARGET TagLib::TagLib) - set(TAGLIB_FOUND ON) - set(TAGLIB_LIBRARIES TagLib::TagLib) - set(HAVE_TAGLIB_DSFFILE ON) - set(HAVE_TAGLIB_DSDIFFFILE ON) - else() - pkg_check_modules(TAGLIB REQUIRED taglib>=1.12) - endif() - set(HAVE_TAGLIB ON) +# TagLib +find_package(TagLib 2.0) +if(TARGET TagLib::TagLib) + set(TAGLIB_FOUND ON) + set(TAGLIB_LIBRARIES TagLib::TagLib) + set(HAVE_TAGLIB_DSFFILE ON) + set(HAVE_TAGLIB_DSDIFFFILE ON) else() - set(HAVE_TAGLIB OFF) -endif() - -# TAGPARSER -if(USE_TAGPARSER) - pkg_check_modules(TAGPARSER REQUIRED tagparser) - set(HAVE_TAGPARSER ON) -else() - set(HAVE_TAGPARSER OFF) + pkg_check_modules(TAGLIB REQUIRED taglib>=1.12) endif() pkg_check_modules(LIBEBUR128 IMPORTED_TARGET libebur128) -if(NOT HAVE_TAGLIB AND NOT HAVE_TAGPARSER) - message(FATAL_ERROR "You need either TagLib or TagParser!") -endif() - # SingleApplication set(KDSINGLEAPPLICATION_NAME "KDSingleApplication-qt${QT_VERSION_MAJOR}") find_package(${KDSINGLEAPPLICATION_NAME} 1.1.0) @@ -443,17 +416,11 @@ add_definitions( if(WIN32) add_definitions(-DUNICODE) - if(MSVC) - add_definitions(-DPROTOBUF_USE_DLLS) - endif() endif() # Subdirectories add_subdirectory(src) add_subdirectory(dist) -add_subdirectory(ext/libstrawberry-common) -add_subdirectory(ext/libstrawberry-tagreader) -add_subdirectory(ext/strawberry-tagreader) if(GTest_FOUND AND GMOCK_LIBRARY AND Qt${QT_VERSION_MAJOR}Test_FOUND) add_subdirectory(tests) diff --git a/README.md b/README.md index 1bc6e6fc1..47bbb4874 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,6 @@ To build Strawberry from source you need the following installed on your system * [GLib](https://developer.gnome.org/glib/) * [Qt 6.4.0 or higher with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/) * [SQLite 3.9 or newer](https://www.sqlite.org) -* [Protobuf](https://developers.google.com/protocol-buffers/) * [ALSA (Required on Linux)](https://www.alsa-project.org/) * [D-Bus (Required on Linux)](https://www.freedesktop.org/wiki/Software/dbus/) * [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org) diff --git a/cmake/Dmg.cmake b/cmake/Dmg.cmake index ff90715c8..74dc55ace 100644 --- a/cmake/Dmg.cmake +++ b/cmake/Dmg.cmake @@ -34,9 +34,9 @@ if(MACDEPLOYQT_EXECUTABLE) COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/ COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/ COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macgstcopy.sh ${CMAKE_BINARY_DIR}/strawberry.app - COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner ${MACDEPLOYQT_CODESIGN} + COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner ${MACDEPLOYQT_CODESIGN} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - DEPENDS strawberry strawberry-tagreader + DEPENDS strawberry ) if(MACDEPLOYCHECK_EXECUTABLE) add_custom_target(deploycheck diff --git a/debian/control b/debian/control index 52f9a384d..dc1e7c988 100644 --- a/debian/control +++ b/debian/control @@ -8,10 +8,8 @@ Build-Depends: debhelper (>= 11), cmake, gcc, g++, - protobuf-compiler, libglib2.0-dev, libdbus-1-dev, - libprotobuf-dev, libboost-dev, libsqlite3-dev, libasound2-dev, diff --git a/debian/copyright b/debian/copyright index 94fbdcfc6..011541775 100644 --- a/debian/copyright +++ b/debian/copyright @@ -9,10 +9,8 @@ Copyright: 2010-2015, David Sansome License: GPL-3+ Files: src/utilities/timeconstants.h - ext/libstrawberry-common/core/logging.cpp - ext/libstrawberry-common/core/logging.h - ext/libstrawberry-common/core/messagehandler.cpp - ext/libstrawberry-common/core/messagehandler.h + src/core/logging.cpp + src/core/logging.h Copyright: 2011, 2012, David Sansome 2018-2022, Jonas Kvinge License: Apache-2.0 @@ -100,8 +98,6 @@ Files: src/core/main.h src/spotify/* src/transcoder/transcoderoptionswavpack.cpp src/transcoder/transcoderoptionswavpack.h - ext/libstrawberry-tagreader/tagreadertagparser.cpp - ext/libstrawberry-tagreader/tagreadertagparser.h src/widgets/resizabletextedit.cpp src/widgets/resizabletextedit.h src/widgets/fancytabdata.cpp diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index e18a4c3ce..bf52bb4f0 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -22,7 +22,7 @@ if(UNIX AND NOT APPLE) install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/) install(FILES unix/org.strawberrymusicplayer.strawberry.desktop DESTINATION share/applications) install(FILES unix/org.strawberrymusicplayer.strawberry.appdata.xml DESTINATION share/metainfo) - install(FILES unix/strawberry.1 unix/strawberry-tagreader.1 DESTINATION share/man/man1) + install(FILES unix/strawberry.1 DESTINATION share/man/man1) endif(UNIX AND NOT APPLE) if(APPLE) diff --git a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml index fb904528d..12ac96efd 100644 --- a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml +++ b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml @@ -6,7 +6,6 @@ GPL-3.0+ strawberry - strawberry-tagreader Strawberry Music Player A music player and collection organizer diff --git a/dist/unix/strawberry-tagreader.1 b/dist/unix/strawberry-tagreader.1 deleted file mode 100644 index c75526f76..000000000 --- a/dist/unix/strawberry-tagreader.1 +++ /dev/null @@ -1,10 +0,0 @@ -.TH STRAWBERRY-TAGREADER "1" -.SH NAME -strawberry-tagreader \- internal tag reader for strawberry -.SH SYNOPSIS -.B strawberry-tagreader -.SH DESCRIPTION -This program is used internally by Strawberry to parse tags in music files without exposing the whole application to crashes caused by malformed files. It is not meant to be run on its own. -.SH "AUTHORS" -.PP -Strawberry main developer is Jonas Kvinge . diff --git a/dist/unix/strawberry.spec.in b/dist/unix/strawberry.spec.in index 6fdd8f58b..b4dded8f3 100644 --- a/dist/unix/strawberry.spec.in +++ b/dist/unix/strawberry.spec.in @@ -40,7 +40,6 @@ BuildRequires: pkgconfig(gio-unix-2.0) BuildRequires: pkgconfig(gthread-2.0) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(alsa) -BuildRequires: pkgconfig(protobuf) BuildRequires: pkgconfig(sqlite3) >= 3.9 BuildRequires: pkgconfig(taglib) BuildRequires: pkgconfig(fftw3) @@ -143,11 +142,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.strawberrymusicpl %doc README.md Changelog %license COPYING %{_bindir}/strawberry -%{_bindir}/strawberry-tagreader %{_datadir}/applications/*.desktop %{_datadir}/icons/hicolor/*/apps/strawberry.* %{_mandir}/man1/%{name}.1.* -%{_mandir}/man1/%{name}-tagreader.1.* %if 0%{?suse_version} %{_datadir}/metainfo/*.appdata.xml %else diff --git a/dist/windows/strawberry.nsi.in b/dist/windows/strawberry.nsi.in index c71f55438..20350a69e 100644 --- a/dist/windows/strawberry.nsi.in +++ b/dist/windows/strawberry.nsi.in @@ -236,7 +236,6 @@ Section "Strawberry" Strawberry ; Common executables File "strawberry.exe" - File "strawberry-tagreader.exe" File "strawberry.ico" File "sqlite3.exe" File "gst-launch-1.0.exe" @@ -330,7 +329,6 @@ Section "Strawberry" Strawberry File "libtasn1-6.dll" File "libtwolame-0.dll" File "libunistring-5.dll" - File "libutf8_validity.dll" File "libvorbis-0.dll" File "libvorbisenc-2.dll" File "libvorbisfile-3.dll" @@ -339,48 +337,6 @@ Section "Strawberry" Strawberry File "libzstd.dll" File "zlib1.dll" - File "libabsl_base.dll" - File "libabsl_city.dll" - File "libabsl_cord.dll" - File "libabsl_cord_internal.dll" - File "libabsl_cordz_handle.dll" - File "libabsl_cordz_info.dll" - File "libabsl_crc32c.dll" - File "libabsl_crc_cord_state.dll" - File "libabsl_crc_internal.dll" - File "libabsl_die_if_null.dll" - File "libabsl_examine_stack.dll" - File "libabsl_hash.dll" - File "libabsl_int128.dll" - File "libabsl_kernel_timeout_internal.dll" - File "libabsl_log_globals.dll" - File "libabsl_log_internal_check_op.dll" - File "libabsl_log_internal_conditions.dll" - File "libabsl_log_internal_format.dll" - File "libabsl_log_internal_globals.dll" - File "libabsl_log_internal_log_sink_set.dll" - File "libabsl_log_internal_message.dll" - File "libabsl_log_internal_nullguard.dll" - File "libabsl_log_internal_proto.dll" - File "libabsl_log_sink.dll" - File "libabsl_low_level_hash.dll" - File "libabsl_malloc_internal.dll" - File "libabsl_raw_hash_set.dll" - File "libabsl_raw_logging_internal.dll" - File "libabsl_spinlock_wait.dll" - File "libabsl_stacktrace.dll" - File "libabsl_status.dll" - File "libabsl_statusor.dll" - File "libabsl_strerror.dll" - File "libabsl_str_format_internal.dll" - File "libabsl_strings.dll" - File "libabsl_strings_internal.dll" - File "libabsl_symbolize.dll" - File "libabsl_synchronization.dll" - File "libabsl_throw_delegate.dll" - File "libabsl_time.dll" - File "libabsl_time_zone.dll" - !ifdef debug File "gdb.exe" File "libexpat-1.dll" @@ -390,7 +346,6 @@ Section "Strawberry" Strawberry File "libpcre2-16d.dll" File "libreadline8.dll" File "libtermcap.dll" - File "libabsl_graphcycles_internal.dll" !else File "libpcre2-8.dll" File "libpcre2-16.dll" @@ -412,7 +367,6 @@ Section "Strawberry" Strawberry !endif File "FLAC.dll" - File "abseil_dll.dll" File "brotlicommon.dll" File "brotlidec.dll" File "chromaprint.dll" @@ -466,7 +420,6 @@ Section "Strawberry" Strawberry File "soup-3.0-0.dll" File "sqlite3.dll" File "tag.dll" - File "utf8_validity.dll" File "vorbis.dll" File "vorbisfile.dll" File "wavpackdll.dll" @@ -504,11 +457,6 @@ Section "Strawberry" Strawberry File "icudt75.dll" File "libfftw3-3.dll" -!ifdef debug - File "libprotobufd.dll" -!else - File "libprotobuf.dll" -!endif !ifdef msvc && debug File "icuin75d.dll" File "icuuc75d.dll" @@ -810,7 +758,6 @@ Section "Uninstall" ; Delete all the files Delete "$INSTDIR\strawberry.exe" - Delete "$INSTDIR\strawberry-tagreader.exe" Delete "$INSTDIR\strawberry.ico" Delete "$INSTDIR\sqlite3.exe" Delete "$INSTDIR\gst-launch-1.0.exe" @@ -905,7 +852,6 @@ Section "Uninstall" Delete "$INSTDIR\libtasn1-6.dll" Delete "$INSTDIR\libtwolame-0.dll" Delete "$INSTDIR\libunistring-5.dll" - Delete "$INSTDIR\libutf8_validity.dll" Delete "$INSTDIR\libvorbis-0.dll" Delete "$INSTDIR\libvorbisenc-2.dll" Delete "$INSTDIR\libvorbisfile-3.dll" @@ -914,48 +860,6 @@ Section "Uninstall" Delete "$INSTDIR\libzstd.dll" Delete "$INSTDIR\zlib1.dll" - Delete "$INSTDIR\libabsl_base.dll" - Delete "$INSTDIR\libabsl_city.dll" - Delete "$INSTDIR\libabsl_cord.dll" - Delete "$INSTDIR\libabsl_cord_internal.dll" - Delete "$INSTDIR\libabsl_cordz_handle.dll" - Delete "$INSTDIR\libabsl_cordz_info.dll" - Delete "$INSTDIR\libabsl_crc32c.dll" - Delete "$INSTDIR\libabsl_crc_cord_state.dll" - Delete "$INSTDIR\libabsl_crc_internal.dll" - Delete "$INSTDIR\libabsl_die_if_null.dll" - Delete "$INSTDIR\libabsl_examine_stack.dll" - Delete "$INSTDIR\libabsl_hash.dll" - Delete "$INSTDIR\libabsl_int128.dll" - Delete "$INSTDIR\libabsl_kernel_timeout_internal.dll" - Delete "$INSTDIR\libabsl_log_globals.dll" - Delete "$INSTDIR\libabsl_log_internal_check_op.dll" - Delete "$INSTDIR\libabsl_log_internal_conditions.dll" - Delete "$INSTDIR\libabsl_log_internal_format.dll" - Delete "$INSTDIR\libabsl_log_internal_globals.dll" - Delete "$INSTDIR\libabsl_log_internal_log_sink_set.dll" - Delete "$INSTDIR\libabsl_log_internal_message.dll" - Delete "$INSTDIR\libabsl_log_internal_nullguard.dll" - Delete "$INSTDIR\libabsl_log_internal_proto.dll" - Delete "$INSTDIR\libabsl_log_sink.dll" - Delete "$INSTDIR\libabsl_low_level_hash.dll" - Delete "$INSTDIR\libabsl_malloc_internal.dll" - Delete "$INSTDIR\libabsl_raw_hash_set.dll" - Delete "$INSTDIR\libabsl_raw_logging_internal.dll" - Delete "$INSTDIR\libabsl_spinlock_wait.dll" - Delete "$INSTDIR\libabsl_stacktrace.dll" - Delete "$INSTDIR\libabsl_status.dll" - Delete "$INSTDIR\libabsl_statusor.dll" - Delete "$INSTDIR\libabsl_strerror.dll" - Delete "$INSTDIR\libabsl_str_format_internal.dll" - Delete "$INSTDIR\libabsl_strings.dll" - Delete "$INSTDIR\libabsl_strings_internal.dll" - Delete "$INSTDIR\libabsl_symbolize.dll" - Delete "$INSTDIR\libabsl_synchronization.dll" - Delete "$INSTDIR\libabsl_throw_delegate.dll" - Delete "$INSTDIR\libabsl_time.dll" - Delete "$INSTDIR\libabsl_time_zone.dll" - !ifdef debug Delete "$INSTDIR\gdb.exe" Delete "$INSTDIR\libexpat-1.dll" @@ -965,7 +869,6 @@ Section "Uninstall" Delete "$INSTDIR\libpcre2-16d.dll" Delete "$INSTDIR\libreadline8.dll" Delete "$INSTDIR\libtermcap.dll" - Delete "$INSTDIR\libabsl_graphcycles_internal.dll" !else Delete "$INSTDIR\libpcre2-8.dll" Delete "$INSTDIR\libpcre2-16.dll" @@ -987,7 +890,6 @@ Section "Uninstall" !endif Delete "$INSTDIR\FLAC.dll" - Delete "$INSTDIR\abseil_dll.dll" Delete "$INSTDIR\brotlicommon.dll" Delete "$INSTDIR\brotlidec.dll" Delete "$INSTDIR\chromaprint.dll" @@ -1041,7 +943,6 @@ Section "Uninstall" Delete "$INSTDIR\soup-3.0-0.dll" Delete "$INSTDIR\sqlite3.dll" Delete "$INSTDIR\tag.dll" - Delete "$INSTDIR\utf8_validity.dll" Delete "$INSTDIR\vorbis.dll" Delete "$INSTDIR\vorbisfile.dll" Delete "$INSTDIR\wavpackdll.dll" @@ -1078,11 +979,6 @@ Section "Uninstall" Delete "$INSTDIR\icudt75.dll" Delete "$INSTDIR\libfftw3-3.dll" -!ifdef debug - Delete "$INSTDIR\libprotobufd.dll" -!else - Delete "$INSTDIR\libprotobuf.dll" -!endif !ifdef msvc && debug Delete "$INSTDIR\icuin75d.dll" Delete "$INSTDIR\icuuc75d.dll" diff --git a/ext/libstrawberry-common/CMakeLists.txt b/ext/libstrawberry-common/CMakeLists.txt deleted file mode 100644 index 979145171..000000000 --- a/ext/libstrawberry-common/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -cmake_minimum_required(VERSION 3.13) - -set(SOURCES - core/logging.cpp - core/messagehandler.cpp - core/messagereply.cpp - core/workerpool.cpp -) - -set(HEADERS - core/logging.h - core/messagehandler.h - core/messagereply.h - core/workerpool.h -) - -qt_wrap_cpp(MOC ${HEADERS}) - -add_library(libstrawberry-common STATIC ${SOURCES} ${MOC}) - -target_include_directories(libstrawberry-common SYSTEM PRIVATE ${GLIB_INCLUDE_DIRS}) -target_include_directories(libstrawberry-common PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_BINARY_DIR}/src -) - -if(Backtrace_FOUND) - target_include_directories(libstrawberry-common SYSTEM PRIVATE ${Backtrace_INCLUDE_DIRS}) -endif() - -target_link_directories(libstrawberry-common PRIVATE ${GLIB_LIBRARY_DIRS}) - -target_link_libraries(libstrawberry-common PRIVATE - ${CMAKE_THREAD_LIBS_INIT} - ${GLIB_LIBRARIES} - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network -) - -if(Backtrace_FOUND) - target_link_libraries(libstrawberry-common PRIVATE ${Backtrace_LIBRARIES}) -endif() diff --git a/ext/libstrawberry-common/core/messagehandler.cpp b/ext/libstrawberry-common/core/messagehandler.cpp deleted file mode 100644 index ead65a929..000000000 --- a/ext/libstrawberry-common/core/messagehandler.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "messagehandler.h" - -#include -#include -#include -#include -#include -#include - -#include "core/logging.h" - -_MessageHandlerBase::_MessageHandlerBase(QIODevice *device, QObject *parent) - : QObject(parent), - device_(nullptr), - flush_abstract_socket_(nullptr), - flush_local_socket_(nullptr), - reading_protobuf_(false), - expected_length_(0), - is_device_closed_(false) { - if (device) { - SetDevice(device); - } -} - -void _MessageHandlerBase::SetDevice(QIODevice *device) { - - device_ = device; - - buffer_.open(QIODevice::ReadWrite); - - QObject::connect(device, &QIODevice::readyRead, this, &_MessageHandlerBase::DeviceReadyRead); - - // Yeah I know. - if (QAbstractSocket *abstractsocket = qobject_cast(device)) { - flush_abstract_socket_ = &QAbstractSocket::flush; - QObject::connect(abstractsocket, &QAbstractSocket::disconnected, this, &_MessageHandlerBase::DeviceClosed); - } - else if (QLocalSocket *localsocket = qobject_cast(device)) { - flush_local_socket_ = &QLocalSocket::flush; - QObject::connect(localsocket, &QLocalSocket::disconnected, this, &_MessageHandlerBase::DeviceClosed); - } - else { - qFatal("Unsupported device type passed to _MessageHandlerBase"); - } - -} - -void _MessageHandlerBase::DeviceReadyRead() { - - while (device_->bytesAvailable() > 0) { - if (!reading_protobuf_) { - // Read the length of the next message - QDataStream s(device_); - s >> expected_length_; - - reading_protobuf_ = true; - } - - // Read some of the message - buffer_.write(device_->read(expected_length_ - buffer_.size())); - - // Did we get everything? - if (buffer_.size() == expected_length_) { - // Parse the message - if (!RawMessageArrived(buffer_.data())) { - qLog(Error) << "Malformed protobuf message"; - device_->close(); - return; - } - - // Clear the buffer - buffer_.close(); - buffer_.setData(QByteArray()); - buffer_.open(QIODevice::ReadWrite); - reading_protobuf_ = false; - } - } - -} - -void _MessageHandlerBase::WriteMessage(const QByteArray &data) { - - QDataStream s(device_); - s << static_cast(data.length()); - s.writeRawData(data.data(), static_cast(data.length())); - - // Sorry. - if (flush_abstract_socket_) { - ((qobject_cast(device_))->*(flush_abstract_socket_))(); - } - else if (flush_local_socket_) { - ((qobject_cast(device_))->*(flush_local_socket_))(); - } - -} - -void _MessageHandlerBase::DeviceClosed() { - is_device_closed_ = true; - AbortAll(); -} diff --git a/ext/libstrawberry-common/core/messagehandler.h b/ext/libstrawberry-common/core/messagehandler.h deleted file mode 100644 index 92989afa1..000000000 --- a/ext/libstrawberry-common/core/messagehandler.h +++ /dev/null @@ -1,176 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - - -#ifndef MESSAGEHANDLER_H -#define MESSAGEHANDLER_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/messagereply.h" - -class QIODevice; - -// Reads and writes uint32 length encoded protobufs to a socket. -// This base QObject is separate from AbstractMessageHandler because moc can't handle templated classes. -// Use AbstractMessageHandler instead. -class _MessageHandlerBase : public QObject { - Q_OBJECT - - public: - // device can be nullptr, in which case you must call SetDevice before writing any messages. - _MessageHandlerBase(QIODevice *device, QObject *parent); - - void SetDevice(QIODevice *device); - - // After this is true, messages cannot be sent to the handler any more. - bool is_device_closed() const { return is_device_closed_; } - - protected Q_SLOTS: - void WriteMessage(const QByteArray &data); - void DeviceReadyRead(); - virtual void DeviceClosed(); - - protected: - virtual bool RawMessageArrived(const QByteArray &data) = 0; - virtual void AbortAll() = 0; - - protected: - typedef bool (QAbstractSocket::*FlushAbstractSocket)(); - typedef bool (QLocalSocket::*FlushLocalSocket)(); - - QIODevice *device_; - FlushAbstractSocket flush_abstract_socket_; - FlushLocalSocket flush_local_socket_; - - bool reading_protobuf_; - quint32 expected_length_; - QBuffer buffer_; - - bool is_device_closed_; -}; - -// Reads and writes uint32 length encoded MessageType messages to a socket. -// You should subclass this and implement the MessageArrived(MessageType) method. -template -class AbstractMessageHandler : public _MessageHandlerBase { - public: - AbstractMessageHandler(QIODevice *device, QObject *parent); - ~AbstractMessageHandler() override { AbstractMessageHandler::AbortAll(); } - - using MessageType = MT; - using ReplyType = MessageReply; - - // Serialises the message and writes it to the socket. - // This version MUST be called from the thread in which the AbstractMessageHandler was created. - void SendMessage(const MessageType &message); - - // Serialises the message and writes it to the socket. - // This version may be called from any thread. - void SendMessageAsync(const MessageType &message); - - // Sends the request message inside and takes ownership of the MessageReply. - // The MessageReply's Finished() signal will be emitted when a reply arrives with the same ID. Must be called from my thread. - void SendRequest(ReplyType *reply); - - // Sets the "id" field of reply to the same as the request, and sends the reply on the socket. Used on the worker side. - void SendReply(const MessageType &request, MessageType *reply); - - protected: - // Called when a message is received from the socket. - virtual void MessageArrived(const MessageType &message) { Q_UNUSED(message); } - - // _MessageHandlerBase - bool RawMessageArrived(const QByteArray &data) override; - void AbortAll() override; - - private: - QMap pending_replies_; -}; - -template -AbstractMessageHandler::AbstractMessageHandler(QIODevice *device, QObject *parent) - : _MessageHandlerBase(device, parent) {} - -template -void AbstractMessageHandler::SendMessage(const MessageType &message) { - Q_ASSERT(QThread::currentThread() == thread()); - - const std::string data = message.SerializeAsString(); - WriteMessage(QByteArray(data.data(), data.size())); -} - -template -void AbstractMessageHandler::SendMessageAsync(const MessageType &message) { - const std::string data = message.SerializeAsString(); - QMetaObject::invokeMethod(this, "WriteMessage", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray(data.data(), data.size()))); -} - -template -void AbstractMessageHandler::SendRequest(ReplyType *reply) { - pending_replies_[reply->id()] = reply; - SendMessage(reply->request_message()); -} - -template -void AbstractMessageHandler::SendReply(const MessageType &request, MessageType *reply) { - reply->set_id(request.id()); - SendMessage(*reply); -} - -template -bool AbstractMessageHandler::RawMessageArrived(const QByteArray &data) { - - MessageType message; - if (!message.ParseFromArray(data.constData(), data.size())) { - return false; - } - - if (pending_replies_.contains(message.id())) { - // This is a reply to a message that we created earlier. - ReplyType *reply = pending_replies_.take(message.id()); - reply->SetReply(message); - } - else { - MessageArrived(message); - } - - return true; - -} - -template -void AbstractMessageHandler::AbortAll() { - - for (ReplyType *reply : pending_replies_) { - reply->Abort(); - } - pending_replies_.clear(); - -} - -#endif // MESSAGEHANDLER_H diff --git a/ext/libstrawberry-common/core/messagereply.cpp b/ext/libstrawberry-common/core/messagereply.cpp deleted file mode 100644 index 502e3a8bf..000000000 --- a/ext/libstrawberry-common/core/messagereply.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include "messagereply.h" - -#include -#include - -#include "core/logging.h" - -_MessageReplyBase::_MessageReplyBase(QObject *parent) - : QObject(parent), finished_(false), success_(false) {} - -bool _MessageReplyBase::WaitForFinished() { - - qLog(Debug) << "Waiting on ID" << id(); - semaphore_.acquire(); - qLog(Debug) << "Acquired ID" << id(); - return success_; - -} - -void _MessageReplyBase::Abort() { - - Q_ASSERT(!finished_); - finished_ = true; - success_ = false; - - Q_EMIT Finished(); - qLog(Debug) << "Releasing ID" << id() << "(aborted)"; - semaphore_.release(); - -} diff --git a/ext/libstrawberry-common/core/messagereply.h b/ext/libstrawberry-common/core/messagereply.h deleted file mode 100644 index dbf887942..000000000 --- a/ext/libstrawberry-common/core/messagereply.h +++ /dev/null @@ -1,99 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef MESSAGEREPLY_H -#define MESSAGEREPLY_H - -#include -#include -#include -#include -#include - -#include "core/logging.h" - -// Base QObject for a reply future class that is returned immediately for requests that will occur in the background. -// Similar to QNetworkReply. Use MessageReply instead. -class _MessageReplyBase : public QObject { - Q_OBJECT - - public: - explicit _MessageReplyBase(QObject *parent = nullptr); - - virtual int id() const = 0; - bool is_finished() const { return finished_; } - bool is_successful() const { return success_; } - - // Waits for the reply to finish by waiting on a semaphore. Never call this from the MessageHandler's thread or it will block forever. - // Returns true if the call was successful. - bool WaitForFinished(); - - void Abort(); - - Q_SIGNALS: - void Finished(); - - protected: - bool finished_; - bool success_; - - QSemaphore semaphore_; -}; - -// A reply future class that is returned immediately for requests that will occur in the background. Similar to QNetworkReply. -template -class MessageReply : public _MessageReplyBase { - public: - explicit MessageReply(const MessageType &request_message, QObject *parent = nullptr); - - int id() const override { return request_message_.id(); } - const MessageType &request_message() const { return request_message_; } - const MessageType &message() const { return reply_message_; } - - void SetReply(const MessageType &message); - - private: - MessageType request_message_; - MessageType reply_message_; -}; - - -template -MessageReply::MessageReply(const MessageType &request_message, QObject *parent) : _MessageReplyBase(parent) { - request_message_.MergeFrom(request_message); -} - -template -void MessageReply::SetReply(const MessageType &message) { - - Q_ASSERT(!finished_); - - reply_message_.MergeFrom(message); - finished_ = true; - success_ = true; - - qLog(Debug) << "Releasing ID" << id() << "(finished)"; - - // Delay the signal as workaround to fix the signal periodically not emitted. - QTimer::singleShot(1, this, &_MessageReplyBase::Finished); - - semaphore_.release(); - -} - -#endif // MESSAGEREPLY_H diff --git a/ext/libstrawberry-common/core/workerpool.cpp b/ext/libstrawberry-common/core/workerpool.cpp deleted file mode 100644 index 467f4c202..000000000 --- a/ext/libstrawberry-common/core/workerpool.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include - -#include "workerpool.h" - -_WorkerPoolBase::_WorkerPoolBase(QObject *parent) : QObject(parent) {} diff --git a/ext/libstrawberry-common/core/workerpool.h b/ext/libstrawberry-common/core/workerpool.h deleted file mode 100644 index b46d3ecfb..000000000 --- a/ext/libstrawberry-common/core/workerpool.h +++ /dev/null @@ -1,466 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef WORKERPOOL_H -#define WORKERPOOL_H - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/logging.h" - -class QLocalSocket; - -// Base class containing signals and slots - required because moc doesn't do templated objects. -class _WorkerPoolBase : public QObject { - Q_OBJECT - - public: - explicit _WorkerPoolBase(QObject *parent = nullptr); - - Q_SIGNALS: - // Emitted when a worker failed to start. This usually happens when the worker wasn't found, or couldn't be executed. - void WorkerFailedToStart(); - - protected Q_SLOTS: - virtual void DoStart() {} - virtual void NewConnection() {} - virtual void ProcessReadyReadStandardOutput() {} - virtual void ProcessReadyReadStandardError() {} - virtual void ProcessError(QProcess::ProcessError) {} - virtual void SendQueuedMessages() {} -}; - - -// Manages a pool of one or more external processes. -// A local socket server is started for each process, and the address is passed to the process as argv[1]. -// The process is expected to connect back to the socket server, and when it does a HandlerType is created for it. -// Instances of HandlerType are created in the WorkerPool's thread. -template -class WorkerPool : public _WorkerPoolBase { - public: - explicit WorkerPool(QObject *parent = nullptr); - ~WorkerPool() override; - - using MessageType = typename HandlerType::MessageType; - using ReplyType = typename HandlerType::ReplyType; - - // Sets the name of the worker executable. This is looked for first in the current directory, and then in $PATH. - // You must call this before calling Start(). - void SetExecutableName(const QString &executable_name); - - // Sets the number of worker process to use. Defaults to 1 <= (processors / 2) <= 2. - void SetWorkerCount(const int count); - - // Sets the prefix to use for the local server (on unix this is a named pipe in /tmp). - // Defaults to QApplication::applicationName(). - // A random number is appended to this name when creating each server. - void SetLocalServerName(const QString &local_server_name); - - // Starts all workers. - void Start(); - - // Fills in the message's "id" field and creates a reply future. - // The message is queued and the WorkerPool's thread will send it to the next available worker. - // Can be called from any thread. - ReplyType *SendMessageWithReply(MessageType *message); - - protected: - // These are all reimplemented slots, they are called on the WorkerPool's thread. - void DoStart() override; - void NewConnection() override; - void ProcessReadyReadStandardOutput() override; - void ProcessReadyReadStandardError() override; - void ProcessError(QProcess::ProcessError error) override; - void SendQueuedMessages() override; - - private: - struct Worker { - Worker() : local_server_(nullptr), local_socket_(nullptr), process_(nullptr), handler_(nullptr) {} - - QLocalServer *local_server_; - QLocalSocket *local_socket_; - QProcess *process_; - HandlerType *handler_; - }; - - // Must only ever be called on my thread. - void StartOneWorker(Worker *worker); - - template - Worker *FindWorker(T Worker::*member, T value) { - for (typename QList::iterator it = workers_.begin(); it != workers_.end(); ++it) { - if ((*it).*member == value) { - return &(*it); - } - } - return nullptr; - } - - template - void DeleteQObjectPointerLater(T **p) { - if (*p) { - (*p)->deleteLater(); - *p = nullptr; - } - } - - // Creates a new reply future for the request with the next sequential ID, - // and sets the request's ID to the ID of the reply. Can be called from any thread - ReplyType *NewReply(MessageType *message); - - // Returns the next handler, or nullptr if there isn't one. Must be called from my thread. - HandlerType *NextHandler() const; - - private: - QString local_server_name_; - QString executable_name_; - QString executable_path_; - - int worker_count_; - mutable int next_worker_; - QList workers_; - - QAtomicInt next_id_; - - QMutex message_queue_mutex_; - QQueue message_queue_; -}; - - -template -WorkerPool::WorkerPool(QObject *parent) - : _WorkerPoolBase(parent), - worker_count_(1), - next_worker_(0), - next_id_(0) { - - local_server_name_ = qApp->applicationName().toLower(); - - if (local_server_name_.isEmpty()) { - local_server_name_ = QStringLiteral("workerpool"); - } - -} - -template -WorkerPool::~WorkerPool() { - - for (const Worker &worker : workers_) { - if (worker.local_socket_ && worker.process_) { - QObject::disconnect(worker.process_, &QProcess::errorOccurred, this, &WorkerPool::ProcessError); - QObject::disconnect(worker.process_, &QProcess::readyReadStandardOutput, this, &WorkerPool::ProcessReadyReadStandardOutput); - QObject::disconnect(worker.process_, &QProcess::readyReadStandardError, this, &WorkerPool::ProcessReadyReadStandardError); - - // The worker is connected. Close his socket and wait for him to exit. - qLog(Debug) << "Closing worker socket"; - worker.local_socket_->close(); - worker.process_->waitForFinished(500); - } - - if (worker.process_ && worker.process_->state() == QProcess::Running) { - // The worker is still running - kill it. - qLog(Debug) << "Killing worker process"; - worker.process_->terminate(); - if (!worker.process_->waitForFinished(500)) { - worker.process_->kill(); - } - } - } - - for (ReplyType *reply : message_queue_) { - reply->Abort(); - } - -} - -template -void WorkerPool::SetWorkerCount(const int count) { - Q_ASSERT(workers_.isEmpty()); - worker_count_ = count; -} - -template -void WorkerPool::SetLocalServerName(const QString &local_server_name) { - Q_ASSERT(workers_.isEmpty()); - local_server_name_ = local_server_name; -} - -template -void WorkerPool::SetExecutableName(const QString &executable_name) { - Q_ASSERT(workers_.isEmpty()); - executable_name_ = executable_name; -} - -template -void WorkerPool::Start() { - QMetaObject::invokeMethod(this, &WorkerPool::DoStart); -} - -template -void WorkerPool::DoStart() { - - Q_ASSERT(workers_.isEmpty()); - Q_ASSERT(!executable_name_.isEmpty()); - Q_ASSERT(QThread::currentThread() == thread()); - - // Find the executable if we can, default to searching $PATH - executable_path_ = executable_name_; - - QStringList search_path; - search_path << QCoreApplication::applicationDirPath(); -#if defined(Q_OS_UNIX) - search_path << QStringLiteral("/usr/libexec"); - search_path << QStringLiteral("/usr/local/libexec"); -#endif -#if defined(Q_OS_MACOS) - search_path << QDir::cleanPath(QCoreApplication::applicationDirPath() + QStringLiteral("/../PlugIns")); -#endif - - for (const QString &path_prefix : std::as_const(search_path)) { - const QString executable_path = path_prefix + QLatin1Char('/') + executable_name_; - if (QFile::exists(executable_path)) { - executable_path_ = executable_path; - qLog(Debug) << "Using worker" << executable_name_ << "from" << path_prefix; - break; - } - } - - if (executable_path_ == executable_name_) { - qLog(Debug) << "Using worker" << executable_name_; - } - - // Start all the workers - for (int i = 0; i < worker_count_; ++i) { - Worker worker; - StartOneWorker(&worker); - - workers_ << worker; - } - -} - -template -void WorkerPool::StartOneWorker(Worker *worker) { - - Q_ASSERT(QThread::currentThread() == thread()); - - DeleteQObjectPointerLater(&worker->local_server_); - DeleteQObjectPointerLater(&worker->local_socket_); - DeleteQObjectPointerLater(&worker->process_); - DeleteQObjectPointerLater(&worker->handler_); - - worker->local_server_ = new QLocalServer(this); - worker->process_ = new QProcess(this); - - QObject::connect(worker->local_server_, &QLocalServer::newConnection, this, &WorkerPool::NewConnection); - QObject::connect(worker->process_, &QProcess::errorOccurred, this, &WorkerPool::ProcessError); - QObject::connect(worker->process_, &QProcess::readyReadStandardOutput, this, &WorkerPool::ProcessReadyReadStandardOutput); - QObject::connect(worker->process_, &QProcess::readyReadStandardError, this, &WorkerPool::ProcessReadyReadStandardError); - - // Create a server, find an unused name and start listening - Q_FOREVER { - const quint32 unique_number = QRandomGenerator::global()->bounded(static_cast(quint64(this) & 0xFFFFFFFF)); - const QString name = QStringLiteral("%1_%2").arg(local_server_name_).arg(unique_number); - - if (worker->local_server_->listen(name)) { - break; - } - } - - qLog(Debug) << "Starting worker" << worker << executable_path_ << worker->local_server_->fullServerName(); - -#ifdef Q_OS_WIN32 - worker->process_->setProcessChannelMode(QProcess::SeparateChannels); -#else - worker->process_->setProcessChannelMode(QProcess::ForwardedChannels); -#endif - - worker->process_->start(executable_path_, QStringList() << worker->local_server_->fullServerName()); -} - -template -void WorkerPool::NewConnection() { - - Q_ASSERT(QThread::currentThread() == thread()); - - QLocalServer *server = qobject_cast(sender()); - - // Find the worker with this server. - Worker *worker = FindWorker(&Worker::local_server_, server); - if (!worker) return; - - qLog(Debug) << "Worker" << worker << "connected to" << server->fullServerName(); - - // Accept the connection. - worker->local_socket_ = server->nextPendingConnection(); - - // We only ever accept one connection per worker, so destroy the server now. - worker->local_socket_->setParent(this); - worker->local_server_->deleteLater(); - worker->local_server_ = nullptr; - - // Create the handler. - worker->handler_ = new HandlerType(worker->local_socket_, this); - - SendQueuedMessages(); - -} - -template -void WorkerPool::ProcessError(QProcess::ProcessError error) { - - Q_ASSERT(QThread::currentThread() == thread()); - - QProcess *process = qobject_cast(sender()); - - // Find the worker with this process. - Worker *worker = FindWorker(&Worker::process_, process); - if (!worker) return; - - switch (error) { - case QProcess::FailedToStart: - // Failed to start errors are bad - it usually means the worker isn't installed. - // Don't restart the process, but tell our owner, who will probably want to do something fatal. - qLog(Error) << "Worker failed to start"; - Q_EMIT WorkerFailedToStart(); - break; - - default: - // On any other error we just restart the process. - qLog(Debug) << "Worker" << worker << "failed with error" << error << "- restarting"; - StartOneWorker(worker); - break; - } - -} - -template -void WorkerPool::ProcessReadyReadStandardOutput() { - - Q_ASSERT(QThread::currentThread() == thread()); - - QProcess *process = qobject_cast(sender()); - QByteArray data = process->readAllStandardOutput(); - - fprintf(stdout, "%s", data.data()); - fflush(stdout); - -} - -template -void WorkerPool::ProcessReadyReadStandardError() { - - Q_ASSERT(QThread::currentThread() == thread()); - - QProcess *process = qobject_cast(sender()); - QByteArray data = process->readAllStandardError(); - - fprintf(stderr, "%s", data.data()); - fflush(stderr); - -} - -template -typename WorkerPool::ReplyType* -WorkerPool::NewReply(MessageType *message) { - - const int id = next_id_.fetchAndAddOrdered(1); - message->set_id(id); - - return new ReplyType(*message); - -} - -template -typename WorkerPool::ReplyType* -WorkerPool::SendMessageWithReply(MessageType *message) { - - ReplyType *reply = NewReply(message); - - // Add the pending reply to the queue - { - QMutexLocker l(&message_queue_mutex_); - message_queue_.enqueue(reply); - } - - // Wake up the main thread - QMetaObject::invokeMethod(this, &WorkerPool::SendQueuedMessages, Qt::QueuedConnection); - - return reply; - -} - -template -void WorkerPool::SendQueuedMessages() { - - QMutexLocker l(&message_queue_mutex_); - - while (!message_queue_.isEmpty()) { - ReplyType *reply = message_queue_.dequeue(); - - // Find a worker for this message - HandlerType *handler = NextHandler(); - if (!handler) { - // No available handlers - put the message on the front of the queue. - message_queue_.prepend(reply); - qLog(Debug) << "No available handlers to process request"; - break; - } - - handler->SendRequest(reply); - } - -} - -template -HandlerType *WorkerPool::NextHandler() const { - - for (int i = 0; i < workers_.count(); ++i) { - const int worker_index = (next_worker_ + i) % workers_.count(); - - if (workers_[worker_index].handler_ && !workers_[worker_index].handler_->is_device_closed()) { - next_worker_ = (worker_index + 1) % workers_.count(); - return workers_[worker_index].handler_; - } - } - - return nullptr; - -} - -#endif // WORKERPOOL_H diff --git a/ext/libstrawberry-tagreader/CMakeLists.txt b/ext/libstrawberry-tagreader/CMakeLists.txt deleted file mode 100644 index 790cd2b7f..000000000 --- a/ext/libstrawberry-tagreader/CMakeLists.txt +++ /dev/null @@ -1,67 +0,0 @@ -cmake_minimum_required(VERSION 3.13) - -# Workaround a bug in protobuf-generate.cmake (https://github.com/protocolbuffers/protobuf/issues/12450) -if(NOT protobuf_PROTOC_EXE) - set(protobuf_PROTOC_EXE "protobuf::protoc") -endif() - -if(NOT Protobuf_LIBRARIES) - set(Protobuf_LIBRARIES protobuf::libprotobuf) -endif() - -set(SOURCES tagreaderbase.cpp tagreadermessages.proto) - -if(HAVE_TAGLIB) - list(APPEND SOURCES tagreadertaglib.cpp tagreadergme.cpp) -endif() - -if(HAVE_TAGPARSER) - list(APPEND SOURCES tagreadertagparser.cpp) -endif() - -add_library(libstrawberry-tagreader STATIC ${PROTO_SOURCES} ${SOURCES}) - -if(NOT MSVC) - target_compile_options(libstrawberry-tagreader PRIVATE -Wno-missing-declarations) -endif() - -target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE - ${GLIB_INCLUDE_DIRS} - ${PROTOBUF_INCLUDE_DIRS} -) - -target_include_directories(libstrawberry-tagreader PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/src - ${CMAKE_BINARY_DIR}/src -) - -target_link_directories(libstrawberry-tagreader PRIVATE - ${GLIB_LIBRARY_DIRS} - ${PROTOBUF_LIBRARY_DIRS} -) - -target_link_libraries(libstrawberry-tagreader PRIVATE - ${GLIB_LIBRARIES} - ${Protobuf_LIBRARIES} - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::Gui - libstrawberry-common -) - -if(HAVE_TAGLIB) - target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS}) - target_link_directories(libstrawberry-tagreader PRIVATE ${TAGLIB_LIBRARY_DIRS}) - target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES}) -endif() - -if(HAVE_TAGPARSER) - target_include_directories(libstrawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS}) - target_link_directories(libstrawberry-tagreader PRIVATE ${TAGPARSER_LIBRARY_DIRS}) - target_link_libraries(libstrawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES}) -endif() - -protobuf_generate(TARGET libstrawberry-tagreader) diff --git a/ext/libstrawberry-tagreader/tagreaderbase.cpp b/ext/libstrawberry-tagreader/tagreaderbase.cpp deleted file mode 100644 index 23722e401..000000000 --- a/ext/libstrawberry-tagreader/tagreaderbase.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/logging.h" -#include "tagreaderbase.h" - -using namespace Qt::StringLiterals; - -TagReaderBase::TagReaderBase() = default; -TagReaderBase::~TagReaderBase() = default; - -QString TagReaderBase::ErrorString(const Result &result) { - - switch (result.error_code) { - case Result::ErrorCode::Success: - return QObject::tr("Success"); - case Result::ErrorCode::Unsupported: - return QObject::tr("File is unsupported"); - case Result::ErrorCode::FilenameMissing: - return QObject::tr("Filename is missing"); - case Result::ErrorCode::FileDoesNotExist: - return QObject::tr("File does not exist"); - case Result::ErrorCode::FileOpenError: - return QObject::tr("File could not be opened"); - case Result::ErrorCode::FileParseError: - return QObject::tr("Could not parse file"); - case Result::ErrorCode::FileSaveError: - return QObject::tr("Could save file"); - case Result::ErrorCode::CustomError: - return result.error; - } - - return QObject::tr("Unknown error"); - -} - -float TagReaderBase::ConvertPOPMRating(const int POPM_rating) { - - if (POPM_rating < 0x01) return 0.0F; - if (POPM_rating < 0x40) return 0.20F; - if (POPM_rating < 0x80) return 0.40F; - if (POPM_rating < 0xC0) return 0.60F; - if (POPM_rating < 0xFC) return 0.80F; - - return 1.0F; - -} - -int TagReaderBase::ConvertToPOPMRating(const float rating) { - - if (rating < 0.20) return 0x00; - if (rating < 0.40) return 0x01; - if (rating < 0.60) return 0x40; - if (rating < 0.80) return 0x80; - if (rating < 1.0) return 0xC0; - - return 0xFF; - -} - -TagReaderBase::Cover TagReaderBase::LoadCoverFromRequest(const QString &song_filename, const spb::tagreader::WriteFileRequest &request) { - - if (!request.has_save_cover() || !request.save_cover()) { - return Cover(); - } - - QString cover_filename; - if (request.has_cover_filename()) { - cover_filename = QString::fromStdString(request.cover_filename()); - } - QByteArray cover_data; - if (request.has_cover_data()) { - cover_data = QByteArray(request.cover_data().data(), static_cast(request.cover_data().size())); - } - QString cover_mime_type; - if (request.has_cover_mime_type()) { - cover_mime_type = QString::fromStdString(request.cover_mime_type()); - } - - return LoadCoverFromRequest(song_filename, cover_filename, cover_data, cover_mime_type); - -} - -TagReaderBase::Cover TagReaderBase::LoadCoverFromRequest(const QString &song_filename, const spb::tagreader::SaveEmbeddedArtRequest &request) { - - QString cover_filename; - if (request.has_cover_filename()) { - cover_filename = QString::fromStdString(request.cover_filename()); - } - QByteArray cover_data; - if (request.has_cover_data()) { - cover_data = QByteArray(request.cover_data().data(), static_cast(request.cover_data().size())); - } - QString cover_mime_type; - if (request.has_cover_mime_type()) { - cover_mime_type = QString::fromStdString(request.cover_mime_type()); - } - - return LoadCoverFromRequest(song_filename, cover_filename, cover_data, cover_mime_type); - -} - -TagReaderBase::Cover TagReaderBase::LoadCoverFromRequest(const QString &song_filename, const QString &cover_filename, QByteArray cover_data, QString cover_mime_type) { - - if (cover_data.isEmpty() && !cover_filename.isEmpty()) { - qLog(Debug) << "Loading cover from" << cover_filename << "for" << song_filename; - QFile file(cover_filename); - if (!file.open(QIODevice::ReadOnly)) { - qLog(Error) << "Failed to open file" << cover_filename << "for reading:" << file.errorString(); - return Cover(); - } - cover_data = file.readAll(); - file.close(); - } - - if (!cover_data.isEmpty()) { - if (cover_mime_type.isEmpty()) { - cover_mime_type = QMimeDatabase().mimeTypeForData(cover_data).name(); - } - if (cover_mime_type == "image/jpeg"_L1) { - qLog(Debug) << "Using cover from JPEG data for" << song_filename; - return Cover(cover_data, cover_mime_type); - } - if (cover_mime_type == "image/png"_L1) { - qLog(Debug) << "Using cover from PNG data for" << song_filename; - return Cover(cover_data, cover_mime_type); - } - // Convert image to JPEG. - qLog(Debug) << "Converting cover to JPEG data for" << song_filename; - QImage cover_image; - if (!cover_image.loadFromData(cover_data)) { - qLog(Error) << "Failed to load image from cover data for" << song_filename; - return Cover(); - } - cover_data.clear(); - QBuffer buffer(&cover_data); - if (buffer.open(QIODevice::WriteOnly)) { - cover_image.save(&buffer, "JPEG"); - buffer.close(); - } - return Cover(cover_data, QStringLiteral("image/jpeg")); - } - - return Cover(); - -} diff --git a/ext/libstrawberry-tagreader/tagreaderbase.h b/ext/libstrawberry-tagreader/tagreaderbase.h deleted file mode 100644 index fba315d6f..000000000 --- a/ext/libstrawberry-tagreader/tagreaderbase.h +++ /dev/null @@ -1,91 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef TAGREADERBASE_H -#define TAGREADERBASE_H - -#include "config.h" - -#include - -#include -#include - -#include "tagreadermessages.pb.h" - -/* - * This class holds all useful methods to read and write tags from/to files. - * You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient) - */ -class TagReaderBase { - public: - explicit TagReaderBase(); - virtual ~TagReaderBase(); - - class Result { - public: - enum class ErrorCode { - Success, - Unsupported, - FilenameMissing, - FileDoesNotExist, - FileOpenError, - FileParseError, - FileSaveError, - CustomError, - }; - Result(const ErrorCode _error_code, const QString &_error = QString()) : error_code(_error_code), error(_error) {} - ErrorCode error_code; - QString error; - bool success() const { return error_code == ErrorCode::Success; } - }; - - class Cover { - public: - explicit Cover(const QByteArray &_data = QByteArray(), const QString &_mime_type = QString()) : data(_data), mime_type(_mime_type) {} - QByteArray data; - QString mime_type; - QString error; - }; - - static QString ErrorString(const Result &result); - - virtual bool IsMediaFile(const QString &filename) const = 0; - - virtual Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const = 0; - virtual Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const = 0; - - virtual Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const = 0; - virtual Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const = 0; - - virtual Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const = 0; - virtual Result SaveSongRatingToFile(const QString &filename, const float rating) const = 0; - - protected: - static float ConvertPOPMRating(const int POPM_rating); - static int ConvertToPOPMRating(const float rating); - - static Cover LoadCoverFromRequest(const QString &song_filename, const spb::tagreader::WriteFileRequest &request); - static Cover LoadCoverFromRequest(const QString &song_filename, const spb::tagreader::SaveEmbeddedArtRequest &request); - - private: - static Cover LoadCoverFromRequest(const QString &song_filename, const QString &cover_filename, QByteArray cover_data, QString cover_mime_type); - - Q_DISABLE_COPY(TagReaderBase) -}; - -#endif // TAGREADERBASE_H diff --git a/ext/libstrawberry-tagreader/tagreadermessages.proto b/ext/libstrawberry-tagreader/tagreadermessages.proto deleted file mode 100644 index 4b44244ae..000000000 --- a/ext/libstrawberry-tagreader/tagreadermessages.proto +++ /dev/null @@ -1,195 +0,0 @@ -syntax = "proto2"; - -package spb.tagreader; - -message SongMetadata { - - enum FileType { - UNKNOWN = 0; - WAV = 1; - FLAC = 2; - WAVPACK = 3; - OGGFLAC = 4; - OGGVORBIS = 5; - OGGOPUS = 6; - OGGSPEEX = 7; - MPEG = 8; - MP4 = 9; - ASF = 10; - AIFF = 11; - MPC = 12; - TRUEAUDIO = 13; - DSF = 14; - DSDIFF = 15; - PCM = 16; - APE = 17; - MOD = 18; - S3M = 19; - XM = 20; - IT = 21; - SPC = 22; - VGM = 23; - CDDA = 90; - STREAM = 91; - } - - optional bool valid = 1; - - optional string title = 2; - optional string album = 3; - optional string artist = 4; - optional string albumartist = 5; - optional int32 track = 6; - optional int32 disc = 7; - optional int32 year = 8; - optional int32 originalyear = 9; - optional string genre = 10; - optional bool compilation = 11; - optional string composer = 12; - optional string performer = 13; - optional string grouping = 14; - optional string comment = 15; - optional string lyrics = 16; - - optional uint64 length_nanosec = 17; - - optional int32 bitrate = 18; - optional int32 samplerate = 19; - optional int32 bitdepth = 20; - - optional string url = 21; - optional string basefilename = 22; - optional FileType filetype = 23; - optional int64 filesize = 24; - optional int64 mtime = 25; - optional int64 ctime = 26; - - optional uint32 playcount = 27; - optional uint32 skipcount = 28; - optional int64 lastplayed = 29; - optional int64 lastseen = 30; - - optional bool art_embedded = 31; - - optional float rating = 32; - - optional string acoustid_id = 33; - optional string acoustid_fingerprint = 34; - - optional string musicbrainz_album_artist_id = 35; // MusicBrainz Release Artist ID (MUSICBRAINZ_ALBUMARTISTID) - optional string musicbrainz_artist_id = 36; // MusicBrainz Artist ID (MUSICBRAINZ_ARTISTID) - optional string musicbrainz_original_artist_id = 37; // MusicBrainz Original Artist ID (MUSICBRAINZ_ORIGINALARTISTID) - optional string musicbrainz_album_id = 38; // MusicBrainz Release ID (MUSICBRAINZ_ALBUMID) - optional string musicbrainz_original_album_id = 39; // MusicBrainz Original Release ID (MUSICBRAINZ_ORIGINALALBUMID) - optional string musicbrainz_recording_id = 40; // MusicBrainz Recording ID (MUSICBRAINZ_TRACKID) - optional string musicbrainz_track_id = 41; // MusicBrainz Track ID (MUSICBRAINZ_RELEASETRACKID) - optional string musicbrainz_disc_id = 42; // MusicBrainz Disc ID (MUSICBRAINZ_DISCID) - optional string musicbrainz_release_group_id = 43; // MusicBrainz Release Group ID (MUSICBRAINZ_RELEASEGROUPID) - optional string musicbrainz_work_id = 44; // MusicBrainz Work ID (MUSICBRAINZ_WORKID) - - optional bool suspicious_tags = 50; - -} - -message IsMediaFileRequest { - optional string filename = 1; -} - -message IsMediaFileResponse { - optional bool success = 1; -} - -message ReadFileRequest { - optional string filename = 1; -} - -message ReadFileResponse { - optional bool success = 1; - optional SongMetadata metadata = 2; - optional string error = 3; -} - -message WriteFileRequest { - optional string filename = 1; - optional bool save_tags = 2; - optional bool save_playcount = 3; - optional bool save_rating = 4; - optional bool save_cover = 5; - optional SongMetadata metadata = 6; - optional string cover_filename = 7; - optional bytes cover_data = 8; - optional string cover_mime_type = 9; -} - -message WriteFileResponse { - optional bool success = 1; - optional string error = 2; -} - -message LoadEmbeddedArtRequest { - optional string filename = 1; -} - -message LoadEmbeddedArtResponse { - optional bool success = 1; - optional bytes data = 2; - optional string error = 3; -} - -message SaveEmbeddedArtRequest { - optional string filename = 1; - optional string cover_filename = 2; - optional bytes cover_data = 3; - optional string cover_mime_type = 4; -} - -message SaveEmbeddedArtResponse { - optional bool success = 1; - optional string error = 2; -} - -message SaveSongPlaycountToFileRequest { - optional string filename = 1; - optional uint32 playcount = 2; -} - -message SaveSongPlaycountToFileResponse { - optional bool success = 1; - optional string error = 2; -} - -message SaveSongRatingToFileRequest { - optional string filename = 1; - optional float rating = 2; -} - -message SaveSongRatingToFileResponse { - optional bool success = 1; - optional string error = 2; -} - -message Message { - optional int32 id = 1; - - optional ReadFileRequest read_file_request = 2; - optional ReadFileResponse read_file_response = 3; - - optional WriteFileRequest write_file_request = 4; - optional WriteFileResponse write_file_response = 5; - - optional IsMediaFileRequest is_media_file_request = 6; - optional IsMediaFileResponse is_media_file_response = 7; - - optional LoadEmbeddedArtRequest load_embedded_art_request = 8; - optional LoadEmbeddedArtResponse load_embedded_art_response = 9; - - optional SaveEmbeddedArtRequest save_embedded_art_request = 10; - optional SaveEmbeddedArtResponse save_embedded_art_response = 11; - - optional SaveSongPlaycountToFileRequest save_song_playcount_to_file_request = 12; - optional SaveSongPlaycountToFileResponse save_song_playcount_to_file_response = 13; - - optional SaveSongRatingToFileRequest save_song_rating_to_file_request = 14; - optional SaveSongRatingToFileResponse save_song_rating_to_file_response = 15; - -} diff --git a/ext/libstrawberry-tagreader/tagreadertaglib.h b/ext/libstrawberry-tagreader/tagreadertaglib.h deleted file mode 100644 index deb79be03..000000000 --- a/ext/libstrawberry-tagreader/tagreadertaglib.h +++ /dev/null @@ -1,147 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2013, David Sansome - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef TAGREADERTAGLIB_H -#define TAGREADERTAGLIB_H - -#include "config.h" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tagreaderbase.h" -#include "tagreadermessages.pb.h" - -#undef TStringToQString -#undef QStringToTString - -class FileRefFactory; - -/* - * This class holds all useful methods to read and write tags from/to files. - * You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient) - */ -class TagReaderTagLib : public TagReaderBase { - public: - explicit TagReaderTagLib(); - ~TagReaderTagLib() override; - - static inline TagLib::String StdStringToTagLibString(const std::string &s) { - return TagLib::String(s.c_str(), TagLib::String::UTF8); - } - - static inline std::string TagLibStringToStdString(const TagLib::String &s) { - return std::string(s.toCString(true), s.length()); - } - - static inline TagLib::String QStringToTagLibString(const QString &s) { - return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8); - } - - static inline QString TagLibStringToQString(const TagLib::String &s) { - return QString::fromUtf8((s).toCString(true)); - } - - static inline void AssignTagLibStringToStdString(const TagLib::String &tstr, std::string *output) { - - const QString qstr = TagLibStringToQString(tstr).trimmed(); - const QByteArray data = qstr.toUtf8(); - output->assign(data.constData(), data.size()); - - } - - bool IsMediaFile(const QString &filename) const override; - - Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override; - Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const override; - - Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const override; - Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const override; - - Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const override; - Result SaveSongRatingToFile(const QString &filename, const float rating) const override; - - private: - spb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const; - - void ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const; - void ParseVorbisComments(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const; - void ParseAPETags(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const; - void ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const; - void ParseASFTags(TagLib::ASF::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const; - void ParseASFAttribute(const TagLib::ASF::AttributeListMap &attributes_map, const char *attribute, std::string *str) const; - - void SetID3v2Tag(TagLib::ID3v2::Tag *tag, const spb::tagreader::SongMetadata &song) const; - void SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const; - void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const; - void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const; - void SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const; - void SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3v2::Tag *tag) const; - - void SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comment, const spb::tagreader::SongMetadata &song) const; - void SetAPETag(TagLib::APE::Tag *tag, const spb::tagreader::SongMetadata &song) const; - void SetASFTag(TagLib::ASF::Tag *tag, const spb::tagreader::SongMetadata &song) const; - void SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const std::string &value) const; - void SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const int value) const; - - QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const; - - static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag); - - void SetPlaycount(TagLib::Ogg::XiphComment *vorbis_comment, const uint playcount) const; - void SetPlaycount(TagLib::APE::Tag *tag, const uint playcount) const; - void SetPlaycount(TagLib::ID3v2::Tag *tag, const uint playcount) const; - void SetPlaycount(TagLib::MP4::Tag *tag, const uint playcount) const; - void SetPlaycount(TagLib::ASF::Tag *tag, const uint playcount) const; - - void SetRating(TagLib::Ogg::XiphComment *vorbis_comment, const float rating) const; - void SetRating(TagLib::APE::Tag *tag, const float rating) const; - void SetRating(TagLib::ID3v2::Tag *tag, const float rating) const; - void SetRating(TagLib::MP4::Tag *tag, const float rating) const; - void SetRating(TagLib::ASF::Tag *tag, const float rating) const; - - void SetEmbeddedArt(TagLib::FLAC::File *flac_file, TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mime_type) const; - void SetEmbeddedArt(TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mime_type) const; - void SetEmbeddedArt(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mime_type) const; - void SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mime_type) const; - - static TagLib::String TagLibStringListToSlashSeparatedString(const TagLib::StringList &taglib_string_list); - - private: - FileRefFactory *factory_; - - Q_DISABLE_COPY(TagReaderTagLib) -}; - -#endif // TAGREADERTAGLIB_H diff --git a/ext/libstrawberry-tagreader/tagreadertagparser.cpp b/ext/libstrawberry-tagreader/tagreadertagparser.cpp deleted file mode 100644 index 24aabda6e..000000000 --- a/ext/libstrawberry-tagreader/tagreadertagparser.cpp +++ /dev/null @@ -1,555 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2021-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include "config.h" - -#include "tagreadertagparser.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/logging.h" -#include "core/messagehandler.h" -#include "utilities/timeconstants.h" - -TagReaderTagParser::TagReaderTagParser() = default; - -bool TagReaderTagParser::IsMediaFile(const QString &filename) const { - - qLog(Debug) << "Checking for valid file" << filename; - - QFileInfo fileinfo(filename); - if (!fileinfo.exists() || fileinfo.suffix().compare(QLatin1String("bak"), Qt::CaseInsensitive) == 0) return false; - - try { - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; - - taginfo.setPath(QFile::encodeName(filename).toStdString()); - taginfo.open(true); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return false; - } - - taginfo.parseTracks(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return false; - } - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - const auto tracks = taginfo.tracks(); - for (TagParser::AbstractTrack *track : tracks) { - if (track->mediaType() == TagParser::MediaType::Audio) { - taginfo.close(); - return true; - } - } - taginfo.close(); - } - catch(...) {} - - return false; - -} - -TagReaderBase::Result TagReaderTagParser::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const { - - qLog(Debug) << "Reading tags from" << filename; - - const QFileInfo fileinfo(filename); - - if (!fileinfo.exists() || fileinfo.suffix().compare(QLatin1String("bak"), Qt::CaseInsensitive) == 0) return Result::ErrorCode::FileParseError; - - const QByteArray url(QUrl::fromLocalFile(filename).toEncoded()); - const QByteArray basefilename = fileinfo.fileName().toUtf8(); - - song->set_basefilename(basefilename.constData(), basefilename.size()); - song->set_url(url.constData(), url.size()); - song->set_filesize(fileinfo.size()); - - song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL); - song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL); - - if (song->ctime() <= 0) { - song->set_ctime(song->mtime()); - } - - song->set_lastseen(QDateTime::currentDateTime().toSecsSinceEpoch()); - - try { - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; - -#ifdef Q_OS_WIN32 - taginfo.setPath(filename.toStdWString().toStdString()); -#else - taginfo.setPath(QFile::encodeName(filename).toStdString()); -#endif - - taginfo.open(true); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTracks(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTags(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - std::vector tracks = taginfo.tracks(); - for (TagParser::AbstractTrack *track : tracks) { - switch (track->format().general) { - case TagParser::GeneralMediaFormat::Flac: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_FLAC); - break; - case TagParser::GeneralMediaFormat::WavPack: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_WAVPACK); - break; - case TagParser::GeneralMediaFormat::MonkeysAudio: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_APE); - break; - case TagParser::GeneralMediaFormat::WindowsMediaAudio: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_ASF); - break; - case TagParser::GeneralMediaFormat::Vorbis: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGVORBIS); - break; - case TagParser::GeneralMediaFormat::Opus: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGOPUS); - break; - case TagParser::GeneralMediaFormat::Speex: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_OGGSPEEX); - break; - case TagParser::GeneralMediaFormat::Mpeg1Audio: - switch (track->format().sub) { - case TagParser::SubFormats::Mpeg1Layer3: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPEG); - break; - case TagParser::SubFormats::None: - default: - break; - } - break; - case TagParser::GeneralMediaFormat::Mpc: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_MPC); - break; - case TagParser::GeneralMediaFormat::Pcm: - song->set_filetype(spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_PCM); - break; - case TagParser::GeneralMediaFormat::Unknown: - default: - break; - } - song->set_length_nanosec(track->duration().totalMilliseconds() * kNsecPerMsec); - song->set_samplerate(track->samplingFrequency()); - song->set_bitdepth(track->bitsPerSample()); - song->set_bitrate(std::max(track->bitrate(), track->maxBitrate())); - } - - if (song->filetype() == spb::tagreader::SongMetadata_FileType::SongMetadata_FileType_UNKNOWN) { - taginfo.close(); - return Result::ErrorCode::Unsupported; - } - - for (TagParser::Tag *tag : taginfo.tags()) { - song->set_albumartist(tag->value(TagParser::KnownField::AlbumArtist).toString(TagParser::TagTextEncoding::Utf8)); - song->set_artist(tag->value(TagParser::KnownField::Artist).toString(TagParser::TagTextEncoding::Utf8)); - song->set_album(tag->value(TagParser::KnownField::Album).toString(TagParser::TagTextEncoding::Utf8)); - song->set_title(tag->value(TagParser::KnownField::Title).toString(TagParser::TagTextEncoding::Utf8)); - song->set_genre(tag->value(TagParser::KnownField::Genre).toString(TagParser::TagTextEncoding::Utf8)); - song->set_composer(tag->value(TagParser::KnownField::Composer).toString(TagParser::TagTextEncoding::Utf8)); - song->set_performer(tag->value(TagParser::KnownField::Performers).toString(TagParser::TagTextEncoding::Utf8)); - song->set_grouping(tag->value(TagParser::KnownField::Grouping).toString(TagParser::TagTextEncoding::Utf8)); - song->set_comment(tag->value(TagParser::KnownField::Comment).toString(TagParser::TagTextEncoding::Utf8)); - song->set_lyrics(tag->value(TagParser::KnownField::Lyrics).toString(TagParser::TagTextEncoding::Utf8)); - song->set_year(tag->value(TagParser::KnownField::RecordDate).toInteger()); - song->set_originalyear(tag->value(TagParser::KnownField::ReleaseDate).toInteger()); - song->set_track(tag->value(TagParser::KnownField::TrackPosition).toInteger()); - song->set_disc(tag->value(TagParser::KnownField::DiskPosition).toInteger()); - if (!tag->value(TagParser::KnownField::Cover).empty() && tag->value(TagParser::KnownField::Cover).dataSize() > 0) { - song->set_art_embedded(true); - } - const float rating = ConvertPOPMRating(tag->value(TagParser::KnownField::Rating)); - if (song->rating() <= 0 && rating > 0.0 && rating <= 1.0) { - song->set_rating(rating); - } - } - - // Set integer fields to -1 if they're not valid - if (song->track() <= 0) { song->set_track(-1); } - if (song->disc() <= 0) { song->set_disc(-1); } - if (song->year() <= 0) { song->set_year(-1); } - if (song->originalyear() <= 0) { song->set_originalyear(-1); } - if (song->samplerate() <= 0) { song->set_samplerate(-1); } - if (song->bitdepth() <= 0) { song->set_bitdepth(-1); } - if (song->bitrate() <= 0) { song->set_bitrate(-1); } - if (song->lastplayed() <= 0) { song->set_lastplayed(-1); } - - song->set_valid(true); - - taginfo.close(); - - return Result::ErrorCode::Success; - - } - catch(...) { - return Result::ErrorCode::FileParseError; - } - -} - -TagReaderBase::Result TagReaderTagParser::WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const { - - if (request.filename().empty()) return Result::ErrorCode::FilenameMissing; - - const spb::tagreader::SongMetadata &song = request.metadata(); - const bool save_tags = request.has_save_tags() && request.save_tags(); - const bool save_playcount = request.has_save_playcount() && request.save_playcount(); - const bool save_rating = request.has_save_rating() && request.save_rating(); - const bool save_cover = request.has_save_cover() && request.save_cover(); - - QStringList save_tags_options; - if (save_tags) { - save_tags_options << QStringLiteral("tags"); - } - if (save_playcount) { - save_tags_options << QStringLiteral("playcount"); - } - if (save_rating) { - save_tags_options << QStringLiteral("rating"); - } - if (save_cover) { - save_tags_options << QStringLiteral("embedded cover"); - } - - qLog(Debug) << "Saving" << save_tags_options.join(QLatin1String(", ")) << "to" << filename; - - const Cover cover = LoadCoverFromRequest(filename, request); - - try { - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; -#ifdef Q_OS_WIN32 - taginfo.setPath(filename.toStdWString().toStdString()); -#else - taginfo.setPath(QFile::encodeName(filename).toStdString()); -#endif - taginfo.open(false); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTracks(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTags(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - if (taginfo.tags().size() <= 0) { - taginfo.createAppropriateTags(); - } - - for (TagParser::Tag *tag : taginfo.tags()) { - if (save_tags) { - tag->setValue(TagParser::KnownField::AlbumArtist, TagParser::TagValue(song.albumartist(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Artist, TagParser::TagValue(song.artist(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Album, TagParser::TagValue(song.album(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Title, TagParser::TagValue(song.title(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Genre, TagParser::TagValue(song.genre(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Composer, TagParser::TagValue(song.composer(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Performers, TagParser::TagValue(song.performer(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Grouping, TagParser::TagValue(song.grouping(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Comment, TagParser::TagValue(song.comment(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::Lyrics, TagParser::TagValue(song.lyrics(), TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding())); - tag->setValue(TagParser::KnownField::TrackPosition, TagParser::TagValue(song.track())); - tag->setValue(TagParser::KnownField::DiskPosition, TagParser::TagValue(song.disc())); - tag->setValue(TagParser::KnownField::RecordDate, TagParser::TagValue(song.year())); - tag->setValue(TagParser::KnownField::ReleaseDate, TagParser::TagValue(song.originalyear())); - } - if (save_playcount) { - SaveSongPlaycountToFile(tag, song.playcount()); - } - if (save_rating) { - SaveSongRatingToFile(tag, song.rating()); - } - if (save_cover) { - SaveEmbeddedArt(tag, cover.data); - } - } - - taginfo.applyChanges(diag, progress); - taginfo.close(); - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - return Result::ErrorCode::Success; - } - catch(...) {} - - return Result::ErrorCode::FileParseError; - -} - -TagReaderBase::Result TagReaderTagParser::LoadEmbeddedArt(const QString &filename, QByteArray &data) const { - - if (filename.isEmpty()) return Result::ErrorCode::FilenameMissing; - - qLog(Debug) << "Loading art from" << filename; - - try { - - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; - -#ifdef Q_OS_WIN32 - taginfo.setPath(filename.toStdWString().toStdString()); -#else - taginfo.setPath(QFile::encodeName(filename).toStdString()); -#endif - - taginfo.open(); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTags(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - for (TagParser::Tag *tag : taginfo.tags()) { - if (!tag->value(TagParser::KnownField::Cover).empty() && tag->value(TagParser::KnownField::Cover).dataSize() > 0) { - data = QByteArray(tag->value(TagParser::KnownField::Cover).dataPointer(), tag->value(TagParser::KnownField::Cover).dataSize()); - taginfo.close(); - return Result::ErrorCode::Success; - } - } - - taginfo.close(); - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - } - catch(...) {} - - return Result::ErrorCode::FileParseError; - -} - -void TagReaderTagParser::SaveEmbeddedArt(TagParser::Tag *tag, const QByteArray &data) const { - - tag->setValue(TagParser::KnownField::Cover, TagParser::TagValue(data.toStdString())); - -} - -TagReaderBase::Result TagReaderTagParser::SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const { - - if (request.filename().empty()) return Result::ErrorCode::FilenameMissing; - - qLog(Debug) << "Saving art to" << filename; - - const Cover cover = LoadCoverFromRequest(filename, request); - - try { - - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; - -#ifdef Q_OS_WIN32 - taginfo.setPath(filename.toStdWString().toStdString()); -#else - taginfo.setPath(QFile::encodeName(filename).toStdString()); -#endif - - taginfo.open(); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTags(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - if (taginfo.tags().size() <= 0) { - taginfo.createAppropriateTags(); - } - - for (TagParser::Tag *tag : taginfo.tags()) { - SaveEmbeddedArt(tag, cover.data); - } - - taginfo.applyChanges(diag, progress); - taginfo.close(); - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - return Result::ErrorCode::Success; - - } - catch(...) {} - - return Result::ErrorCode::FileParseError; - -} - -void TagReaderTagParser::SaveSongPlaycountToFile(TagParser::Tag *tag, const uint playcount) const { - - Q_UNUSED(tag); - Q_UNUSED(playcount); - -} - -TagReaderBase::Result TagReaderTagParser::SaveSongPlaycountToFile(const QString &filename, const uint playcount) const { - - Q_UNUSED(filename); - Q_UNUSED(playcount); - - return Result::ErrorCode::Unsupported; - -} - -void TagReaderTagParser::SaveSongRatingToFile(TagParser::Tag *tag, const float rating) const { - - tag->setValue(TagParser::KnownField::Rating, TagParser::TagValue(ConvertToPOPMRating(rating))); - -} - -TagReaderBase::Result TagReaderTagParser::SaveSongRatingToFile(const QString &filename, const float rating) const { - - if (filename.isEmpty()) return Result::ErrorCode::FilenameMissing; - - qLog(Debug) << "Saving song rating to" << filename; - - try { - TagParser::MediaFileInfo taginfo; - TagParser::Diagnostics diag; - TagParser::AbortableProgressFeedback progress; - #ifdef Q_OS_WIN32 - taginfo.setPath(filename.toStdWString().toStdString()); - #else - taginfo.setPath(QFile::encodeName(filename).toStdString()); - #endif - taginfo.open(false); - - taginfo.parseContainerFormat(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTracks(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - taginfo.parseTags(diag, progress); - if (progress.isAborted()) { - taginfo.close(); - return Result::ErrorCode::FileParseError; - } - - if (taginfo.tags().size() <= 0) { - taginfo.createAppropriateTags(); - } - - for (TagParser::Tag *tag : taginfo.tags()) { - SaveSongRatingToFile(tag, rating); - } - - taginfo.applyChanges(diag, progress); - taginfo.close(); - - for (const TagParser::DiagMessage &msg : diag) { - qLog(Debug) << QString::fromStdString(msg.message()); - } - - return Result::ErrorCode::Success; - } - catch(...) {} - - return Result::ErrorCode::FileParseError; - -} diff --git a/ext/libstrawberry-tagreader/tagreadertagparser.h b/ext/libstrawberry-tagreader/tagreadertagparser.h deleted file mode 100644 index 41e682d23..000000000 --- a/ext/libstrawberry-tagreader/tagreadertagparser.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2021-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef TAGREADERTAGPARSER_H -#define TAGREADERTAGPARSER_H - -#include "config.h" - -#include - -#include - -#include -#include - -#include "tagreadermessages.pb.h" -#include "tagreaderbase.h" - -/* - * This class holds all useful methods to read and write tags from/to files. - * You should not use it directly in the main process but rather use a TagReaderWorker process (using TagReaderClient) - */ -class TagReaderTagParser : public TagReaderBase { - public: - explicit TagReaderTagParser(); - - bool IsMediaFile(const QString &filename) const override; - - Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override; - Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const override; - - Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const override; - Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const override; - - Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const override; - Result SaveSongRatingToFile(const QString &filename, const float rating) const override; - - private: - void SaveSongPlaycountToFile(TagParser::Tag *tag, const uint playcount) const; - void SaveSongRatingToFile(TagParser::Tag *tag, const float rating) const; - void SaveEmbeddedArt(TagParser::Tag *tag, const QByteArray &data) const; - - public: - Q_DISABLE_COPY(TagReaderTagParser) -}; - -#endif // TAGREADERTAGPARSER_H diff --git a/ext/strawberry-tagreader/CMakeLists.txt b/ext/strawberry-tagreader/CMakeLists.txt deleted file mode 100644 index 8ee5d6157..000000000 --- a/ext/strawberry-tagreader/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -cmake_minimum_required(VERSION 3.13) - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) - -set(SOURCES main.cpp tagreaderworker.cpp) -set(HEADERS tagreaderworker.h) - -qt_wrap_cpp(MOC ${HEADERS}) - -add_executable(strawberry-tagreader ${SOURCES} ${MOC} ${QRC}) - -target_include_directories(strawberry-tagreader SYSTEM PRIVATE - ${GLIB_INCLUDE_DIRS} - ${PROTOBUF_INCLUDE_DIRS} -) - -target_include_directories(strawberry-tagreader PRIVATE - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/src -) - -target_link_directories(strawberry-tagreader PRIVATE ${GLIB_LIBRARY_DIRS}) - -target_link_libraries(strawberry-tagreader PRIVATE - ${GLIB_LIBRARIES} - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network - libstrawberry-common - libstrawberry-tagreader -) - -if(HAVE_TAGLIB) - target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGLIB_INCLUDE_DIRS}) - target_link_directories(strawberry-tagreader PRIVATE ${TAGLIB_LIBRARY_DIRS}) - target_link_libraries(strawberry-tagreader PRIVATE ${TAGLIB_LIBRARIES}) -endif() - -if(HAVE_TAGPARSER) - target_include_directories(strawberry-tagreader SYSTEM PRIVATE ${TAGPARSER_INCLUDE_DIRS}) - target_link_directories(strawberry-tagreader PRIVATE ${TAGPARSER_LIBRARY_DIRS}) - target_link_libraries(strawberry-tagreader PRIVATE ${TAGPARSER_LIBRARIES}) -endif() - -if(FREEBSD) - target_link_libraries(strawberry-tagreader PRIVATE execinfo) -endif() - -if(APPLE) - target_link_libraries(strawberry-tagreader PRIVATE /System/Library/Frameworks/Foundation.framework) -endif() - -if(APPLE) - install(TARGETS strawberry-tagreader DESTINATION ${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns) -else() - install(TARGETS strawberry-tagreader RUNTIME DESTINATION bin) -endif() diff --git a/ext/strawberry-tagreader/main.cpp b/ext/strawberry-tagreader/main.cpp deleted file mode 100644 index 4cd5df87a..000000000 --- a/ext/strawberry-tagreader/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2021, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include "config.h" - -#include - -#include - -#include -#include -#include -#include -#include - -#include "core/logging.h" -#include "tagreaderworker.h" - -int main(int argc, char **argv) { - - QCoreApplication a(argc, argv); - QStringList args(a.arguments()); - - if (args.count() != 2) { - std::cerr << "This program is used internally by Strawberry to parse tags in music files\n" - "without exposing the whole application to crashes caused by malformed\n" - "files. It is not meant to be run on its own.\n"; - return 1; - } - - logging::Init(); - qLog(Info) << "TagReader worker connecting to" << args[1]; - - // Connect to the parent process. - QLocalSocket socket; - socket.connectToServer(args[1]); - if (!socket.waitForConnected(2000)) { - std::cerr << "Failed to connect to the parent process.\n"; - return 1; - } - - TagReaderWorker worker(&socket); - - return a.exec(); - -} diff --git a/ext/strawberry-tagreader/tagreaderworker.cpp b/ext/strawberry-tagreader/tagreaderworker.cpp deleted file mode 100644 index 0bfd35739..000000000 --- a/ext/strawberry-tagreader/tagreaderworker.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "tagreaderworker.h" - -#ifdef HAVE_TAGLIB -# include "tagreadertaglib.h" -# include "tagreadergme.h" -#endif - -#ifdef HAVE_TAGPARSER -# include "tagreadertagparser.h" -#endif - -using std::make_shared; -using std::shared_ptr; - -TagReaderWorker::TagReaderWorker(QIODevice *socket, QObject *parent) - : AbstractMessageHandler(socket, parent) { - -#ifdef HAVE_TAGLIB - tagreaders_ << make_shared(); - tagreaders_ << make_shared(); -#endif - -#ifdef HAVE_TAGPARSER - tagreaders_ << make_shared(); -#endif - -} - -void TagReaderWorker::MessageArrived(const spb::tagreader::Message &message) { - - spb::tagreader::Message reply; - - HandleMessage(message, reply); - SendReply(message, &reply); - -} - -void TagReaderWorker::DeviceClosed() { - - AbstractMessageHandler::DeviceClosed(); - - QCoreApplication::exit(); - -} - -void TagReaderWorker::HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply) { - - for (shared_ptr reader : std::as_const(tagreaders_)) { - - if (message.has_is_media_file_request()) { - const QString filename = QString::fromStdString(message.is_media_file_request().filename()); - const bool success = reader->IsMediaFile(filename); - reply.mutable_is_media_file_response()->set_success(success); - if (success) { - return; - } - } - if (message.has_read_file_request()) { - const QString filename = QString::fromStdString(message.read_file_request().filename()); - spb::tagreader::ReadFileResponse *response = reply.mutable_read_file_response(); - const TagReaderBase::Result result = reader->ReadFile(filename, response->mutable_metadata()); - response->set_success(result.success()); - if (result.success()) { - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - if (message.has_write_file_request()) { - const QString filename = QString::fromStdString(message.write_file_request().filename()); - const TagReaderBase::Result result = reader->WriteFile(filename, message.write_file_request()); - spb::tagreader::WriteFileResponse *response = reply.mutable_write_file_response(); - response->set_success(result.success()); - if (result.success()) { - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - if (message.has_load_embedded_art_request()) { - const QString filename = QString::fromStdString(message.load_embedded_art_request().filename()); - QByteArray data; - const TagReaderBase::Result result = reader->LoadEmbeddedArt(filename, data); - spb::tagreader::LoadEmbeddedArtResponse *response = reply.mutable_load_embedded_art_response(); - response->set_success(result.success()); - if (result.success()) { - response->set_data(data.toStdString()); - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - if (message.has_save_embedded_art_request()) { - const QString filename = QString::fromStdString(message.save_embedded_art_request().filename()); - const TagReaderBase::Result result = reader->SaveEmbeddedArt(filename, message.save_embedded_art_request()); - spb::tagreader::SaveEmbeddedArtResponse *response = reply.mutable_save_embedded_art_response(); - response->set_success(result.success()); - if (result.success()) { - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - if (message.has_save_song_playcount_to_file_request()) { - const QString filename = QString::fromStdString(message.save_song_playcount_to_file_request().filename()); - const TagReaderBase::Result result = reader->SaveSongPlaycountToFile(filename, message.save_song_playcount_to_file_request().playcount()); - spb::tagreader::SaveSongPlaycountToFileResponse *response = reply.mutable_save_song_playcount_to_file_response(); - response->set_success(result.success()); - if (result.success()) { - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - if (message.has_save_song_rating_to_file_request()) { - const QString filename = QString::fromStdString(message.save_song_rating_to_file_request().filename()); - const TagReaderBase::Result result = reader->SaveSongRatingToFile(filename, message.save_song_rating_to_file_request().rating()); - spb::tagreader::SaveSongRatingToFileResponse *response = reply.mutable_save_song_rating_to_file_response(); - response->set_success(result.success()); - if (result.success()) { - if (response->has_error()) { - response->clear_error(); - } - return; - } - else { - if (!response->has_error()) { - response->set_error(TagReaderBase::ErrorString(result).toStdString()); - } - } - } - - } - -} diff --git a/ext/strawberry-tagreader/tagreaderworker.h b/ext/strawberry-tagreader/tagreaderworker.h deleted file mode 100644 index 441d78f1e..000000000 --- a/ext/strawberry-tagreader/tagreaderworker.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Strawberry. - Copyright 2011, David Sansome - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ - -#ifndef TAGREADERWORKER_H -#define TAGREADERWORKER_H - -#include "config.h" - -#include - -#include -#include - -#include "core/messagehandler.h" - -#include "tagreadermessages.pb.h" - -class QIODevice; -class TagReaderBase; - -using std::shared_ptr; - -class TagReaderWorker : public AbstractMessageHandler { - Q_OBJECT - - public: - explicit TagReaderWorker(QIODevice *socket, QObject *parent = nullptr); - - protected: - void MessageArrived(const spb::tagreader::Message &message) override; - void DeviceClosed() override; - - private: - void HandleMessage(const spb::tagreader::Message &message, spb::tagreader::Message &reply); - - QList> tagreaders_; -}; - -#endif // TAGREADERWORKER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c88bfebaf..e2a1dc3de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ if(HAVE_TRANSLATIONS) endif() set(SOURCES + core/logging.cpp core/mainwindow.cpp core/application.cpp core/player.cpp @@ -31,7 +32,6 @@ set(SOURCES core/songloader.cpp core/stylehelper.cpp core/stylesheetloader.cpp - core/tagreaderclient.cpp core/taskmanager.cpp core/thread.cpp core/urlhandler.cpp @@ -63,6 +63,27 @@ set(SOURCES utilities/screenutils.cpp utilities/textencodingutils.cpp + tagreader/tagreaderclient.cpp + tagreader/tagreaderresult.cpp + tagreader/tagreaderbase.cpp + tagreader/tagreadertaglib.cpp + tagreader/tagreadergme.cpp + tagreader/tagreaderrequest.cpp + tagreader/tagreaderismediafilerequest.cpp + tagreader/tagreaderreadfilerequest.cpp + tagreader/tagreaderwritefilerequest.cpp + tagreader/tagreaderloadcoverdatarequest.cpp + tagreader/tagreaderloadcoverimagerequest.cpp + tagreader/tagreadersavecoverrequest.cpp + tagreader/tagreadersaveplaycountrequest.cpp + tagreader/tagreadersaveratingrequest.cpp + tagreader/albumcovertagdata.cpp + tagreader/savetagcoverdata.cpp + tagreader/tagreaderreply.cpp + tagreader/tagreaderreadfilereply.cpp + tagreader/tagreaderloadcoverdatareply.cpp + tagreader/tagreaderloadcoverimagereply.cpp + filterparser/filterparser.cpp filterparser/filtertree.cpp @@ -319,6 +340,7 @@ set(SOURCES ) set(HEADERS + core/logging.h core/mainwindow.h core/application.h core/player.h @@ -333,7 +355,6 @@ set(HEADERS core/qtfslistener.h core/settings.h core/songloader.h - core/tagreaderclient.h core/taskmanager.h core/thread.h core/urlhandler.h @@ -344,6 +365,12 @@ set(HEADERS core/stylesheetloader.h core/localredirectserver.h + tagreader/tagreaderclient.h + tagreader/tagreaderreply.h + tagreader/tagreaderreadfilereply.h + tagreader/tagreaderloadcoverdatareply.h + tagreader/tagreaderloadcoverimagereply.h + engine/enginebase.h engine/devicefinders.h @@ -1059,8 +1086,8 @@ target_include_directories(strawberry_lib SYSTEM PUBLIC ${GLIB_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} ${SQLITE_INCLUDE_DIRS} - ${PROTOBUF_INCLUDE_DIRS} ${ICU_INCLUDE_DIRS} + ${TAGLIB_INCLUDE_DIRS} ) if(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H) @@ -1072,9 +1099,6 @@ target_include_directories(strawberry_lib PUBLIC ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader ${SINGLEAPPLICATION_INCLUDE_DIRS} ) @@ -1083,9 +1107,9 @@ target_link_directories(strawberry_lib PUBLIC ${GLIB_LIBRARY_DIRS} ${GOBJECT_LIBRARY_DIRS} ${SQLITE_LIBRARY_DIRS} - ${PROTOBUF_LIBRARY_DIRS} ${SINGLEAPPLICATION_LIBRARY_DIRS} ${ICU_LIBRARY_DIRS} + ${TAGLIB_LIBRARY_DIRS} ) target_link_libraries(strawberry_lib PUBLIC @@ -1094,16 +1118,14 @@ target_link_libraries(strawberry_lib PUBLIC ${GOBJECT_LIBRARIES} ${SQLITE_LIBRARIES} ${ICU_LIBRARIES} + ${TAGLIB_LIBRARIES} Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Sql - ${Protobuf_LIBRARIES} ${SINGLEAPPLICATION_LIBRARIES} - libstrawberry-common - libstrawberry-tagreader ) if(HAVE_DBUS) @@ -1268,9 +1290,6 @@ endif() target_link_libraries(strawberry PRIVATE strawberry_lib) -# macdeploy.py relies on the blob being built first. -add_dependencies(strawberry strawberry-tagreader) - if(NOT APPLE) install(TARGETS strawberry RUNTIME DESTINATION bin) endif() diff --git a/src/collection/collection.cpp b/src/collection/collection.cpp index 2cfde0b37..9546c597e 100644 --- a/src/collection/collection.cpp +++ b/src/collection/collection.cpp @@ -33,11 +33,11 @@ #include "core/application.h" #include "core/taskmanager.h" #include "core/database.h" -#include "core/tagreaderclient.h" #include "core/thread.h" #include "core/song.h" #include "core/logging.h" #include "core/settings.h" +#include "tagreader/tagreaderclient.h" #include "utilities/threadutils.h" #include "collection.h" #include "collectionwatcher.h" @@ -216,7 +216,7 @@ void SCollection::SyncPlaycountAndRatingToFiles() { void SCollection::SongsPlaycountChanged(const SongList &songs, const bool save_tags) { if (save_tags || save_playcounts_to_files_) { - app_->tag_reader_client()->SaveSongsPlaycount(songs); + app_->tag_reader_client()->SaveSongsPlaycountAsync(songs); } } @@ -224,7 +224,7 @@ void SCollection::SongsPlaycountChanged(const SongList &songs, const bool save_t void SCollection::SongsRatingChanged(const SongList &songs, const bool save_tags) { if (save_tags || save_ratings_to_files_) { - app_->tag_reader_client()->SaveSongsRating(songs); + app_->tag_reader_client()->SaveSongsRatingAsync(songs); } } diff --git a/src/collection/collectionplaylistitem.cpp b/src/collection/collectionplaylistitem.cpp index 84df5834c..9c28035a4 100644 --- a/src/collection/collectionplaylistitem.cpp +++ b/src/collection/collectionplaylistitem.cpp @@ -26,7 +26,7 @@ #include "core/logging.h" #include "collectionplaylistitem.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" class SqlRow; @@ -42,9 +42,9 @@ QUrl CollectionPlaylistItem::Url() const { return song_.url(); } void CollectionPlaylistItem::Reload() { - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); if (!result.success()) { - qLog(Error) << "Could not reload file" << song_.url() << result.error; + qLog(Error) << "Could not reload file" << song_.url() << result.error_string(); return; } UpdateTemporaryMetadata(song_); diff --git a/src/collection/collectionwatcher.cpp b/src/collection/collectionwatcher.cpp index cc24fce06..49a79ddb9 100644 --- a/src/collection/collectionwatcher.cpp +++ b/src/collection/collectionwatcher.cpp @@ -47,11 +47,11 @@ #include "core/filesystemwatcherinterface.h" #include "core/logging.h" -#include "core/tagreaderclient.h" #include "core/taskmanager.h" #include "core/settings.h" #include "utilities/imageutils.h" #include "utilities/timeconstants.h" +#include "tagreader/tagreaderclient.h" #include "collectiondirectory.h" #include "collectionbackend.h" #include "collectionwatcher.h" @@ -866,7 +866,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file, } Song song_on_disk(source_); - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(file, &song_on_disk); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(file, &song_on_disk); if (result.success() && song_on_disk.is_valid()) { song_on_disk.set_source(source_); song_on_disk.set_directory_id(t->dir()); @@ -919,7 +919,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path } else { // It's a normal media file Song song(source_); - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(file, &song); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(file, &song); if (result.success() && song.is_valid()) { song.set_source(source_); PerformEBUR128Analysis(song); diff --git a/src/config.h.in b/src/config.h.in index f74d6bf22..0b507b11f 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -37,10 +37,8 @@ #cmakedefine HAVE_KEYSYMDEF_H #cmakedefine HAVE_XF86KEYSYM_H -#cmakedefine HAVE_TAGLIB #cmakedefine HAVE_TAGLIB_DSFFILE #cmakedefine HAVE_TAGLIB_DSDIFFFILE -#cmakedefine HAVE_TAGPARSER #cmakedefine USE_BUNDLE diff --git a/src/core/application.cpp b/src/core/application.cpp index d119df442..e98a789eb 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -36,12 +36,11 @@ #include "shared_ptr.h" #include "lazy.h" -#include "tagreaderclient.h" #include "database.h" #include "taskmanager.h" #include "player.h" #include "networkaccessmanager.h" - +#include "tagreader/tagreaderclient.h" #include "engine/devicefinders.h" #ifndef Q_OS_WIN # include "device/devicemanager.h" @@ -118,7 +117,6 @@ class ApplicationImpl { tag_reader_client_([app](){ TagReaderClient *client = new TagReaderClient(); app->MoveToNewThread(client); - client->Start(); return client; }), database_([app]() { diff --git a/ext/libstrawberry-common/core/logging.cpp b/src/core/logging.cpp similarity index 100% rename from ext/libstrawberry-common/core/logging.cpp rename to src/core/logging.cpp diff --git a/ext/libstrawberry-common/core/logging.h b/src/core/logging.h similarity index 100% rename from ext/libstrawberry-common/core/logging.h rename to src/core/logging.h diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 1df127623..65f73a5b1 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -2177,21 +2177,20 @@ void MainWindow::RenumberTracks() { Song song = item->OriginalMetadata(); if (song.IsEditable()) { song.set_track(track); - TagReaderReply *reply = TagReaderClient::Instance()->WriteFile(song.url().toLocalFile(), song); + TagReaderReplyPtr reply = TagReaderClient::Instance()->WriteFileAsync(song.url().toLocalFile(), song); QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection); } ++track; } } -void MainWindow::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx) { +void MainWindow::SongSaveComplete(TagReaderReplyPtr reply, const QPersistentModelIndex &idx) { - if (reply->is_successful() && idx.isValid()) { + if (reply->success() && idx.isValid()) { app_->playlist_manager()->current()->ReloadItems(QList() << idx.row()); } - reply->deleteLater(); } @@ -2209,9 +2208,9 @@ void MainWindow::SelectionSetValue() { Song song = item->OriginalMetadata(); if (!song.is_valid()) continue; if (song.url().isLocalFile() && Playlist::set_column_value(song, column, column_value)) { - TagReaderReply *reply = TagReaderClient::Instance()->WriteFile(song.url().toLocalFile(), song); + TagReaderReplyPtr reply = TagReaderClient::Instance()->WriteFileAsync(song.url().toLocalFile(), song); QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection); } else if (song.source() == Song::Source::Stream) { app_->playlist_manager()->current()->setData(source_index, column_value, 0); diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index b55f31b16..a4369bc85 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -51,8 +51,8 @@ #include "lazy.h" #include "platforminterface.h" #include "song.h" -#include "tagreaderclient.h" #include "settings.h" +#include "tagreader/tagreaderclient.h" #include "engine/enginebase.h" #include "osd/osdbase.h" #include "playlist/playlist.h" @@ -218,7 +218,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { void PlayingWidgetPositionChanged(const bool above_status_bar); - void SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx); + void SongSaveComplete(TagReaderReplyPtr reply, const QPersistentModelIndex &idx); void ShowCoverManager(); void ShowEqualizer(); diff --git a/src/core/song.cpp b/src/core/song.cpp index 128bc3fa4..fed0e8982 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -48,6 +48,8 @@ #include #include +#include + #include "core/iconloader.h" #include "engine/enginemetadata.h" #include "utilities/strutils.h" @@ -55,13 +57,13 @@ #include "utilities/coverutils.h" #include "utilities/timeconstants.h" #include "utilities/sqlhelper.h" + #include "song.h" #include "sqlquery.h" #include "sqlrow.h" #ifdef HAVE_DBUS # include "mpris_common.h" #endif -#include "tagreadermessages.pb.h" using namespace Qt::StringLiterals; @@ -482,6 +484,29 @@ const QString &Song::musicbrainz_work_id() const { return d->musicbrainz_work_id std::optional Song::ebur128_integrated_loudness_lufs() const { return d->ebur128_integrated_loudness_lufs_; } std::optional Song::ebur128_loudness_range_lu() const { return d->ebur128_loudness_range_lu_; } +QString *Song::mutable_title() { return &d->title_; } +QString *Song::mutable_album() { return &d->album_; } +QString *Song::mutable_artist() { return &d->artist_; } +QString *Song::mutable_albumartist() { return &d->albumartist_; } +QString *Song::mutable_genre() { return &d->genre_; } +QString *Song::mutable_composer() { return &d->composer_; } +QString *Song::mutable_performer() { return &d->performer_; } +QString *Song::mutable_grouping() { return &d->grouping_; } +QString *Song::mutable_comment() { return &d->comment_; } +QString *Song::mutable_lyrics() { return &d->lyrics_; } +QString *Song::mutable_acoustid_id() { return &d->acoustid_id_; } +QString *Song::mutable_acoustid_fingerprint() { return &d->acoustid_fingerprint_; } +QString *Song::mutable_musicbrainz_album_artist_id() { return &d->musicbrainz_album_artist_id_; } +QString *Song::mutable_musicbrainz_artist_id() { return &d->musicbrainz_artist_id_; } +QString *Song::mutable_musicbrainz_original_artist_id() { return &d->musicbrainz_original_artist_id_; } +QString *Song::mutable_musicbrainz_album_id() { return &d->musicbrainz_album_id_; } +QString *Song::mutable_musicbrainz_original_album_id() { return &d->musicbrainz_original_album_id_; } +QString *Song::mutable_musicbrainz_recording_id() { return &d->musicbrainz_recording_id_; } +QString *Song::mutable_musicbrainz_track_id() { return &d->musicbrainz_track_id_; } +QString *Song::mutable_musicbrainz_disc_id() { return &d->musicbrainz_disc_id_; } +QString *Song::mutable_musicbrainz_release_group_id() { return &d->musicbrainz_release_group_id_; } +QString *Song::mutable_musicbrainz_work_id() { return &d->musicbrainz_work_id_; } + bool Song::init_from_file() const { return d->init_from_file_; } const QString &Song::title_sortable() const { return d->title_sortable_; } @@ -503,7 +528,7 @@ void Song::set_disc(const int v) { d->disc_ = v; } void Song::set_year(const int v) { d->year_ = v; } void Song::set_originalyear(const int v) { d->originalyear_ = v; } void Song::set_genre(const QString &v) { d->genre_ = v; } -void Song::set_compilation(bool v) { d->compilation_ = v; } +void Song::set_compilation(const bool v) { d->compilation_ = v; } void Song::set_composer(const QString &v) { d->composer_ = v; } void Song::set_performer(const QString &v) { d->performer_ = v; } void Song::set_grouping(const QString &v) { d->grouping_ = v; } @@ -571,6 +596,59 @@ void Song::set_ebur128_loudness_range_lu(const std::optional v) { d->ebu void Song::set_stream_url(const QUrl &v) { d->stream_url_ = v; } +void Song::set_title(const TagLib::String &v) { + + const QString title = TagLibStringToQString(v); + d->title_sortable_ = sortable(title); + d->title_ = title; + +} + +void Song::set_album(const TagLib::String &v) { + + const QString album = TagLibStringToQString(v); + d->album_sortable_ = sortable(album); + d->album_ = album; + +} +void Song::set_artist(const TagLib::String &v) { + + const QString artist = TagLibStringToQString(v); + d->artist_sortable_ = sortable(artist); + d->artist_ = artist; + +} + +void Song::set_albumartist(const TagLib::String &v) { + + const QString albumartist = TagLibStringToQString(v); + d->albumartist_sortable_ = sortable(albumartist); + d->albumartist_ = albumartist; + +} + +void Song::set_genre(const TagLib::String &v) { d->genre_ = TagLibStringToQString(v); } +void Song::set_composer(const TagLib::String &v) { d->composer_ = TagLibStringToQString(v); } +void Song::set_performer(const TagLib::String &v) { d->performer_ = TagLibStringToQString(v); } +void Song::set_grouping(const TagLib::String &v) { d->grouping_ = TagLibStringToQString(v); } +void Song::set_comment(const TagLib::String &v) { d->comment_ = TagLibStringToQString(v); } +void Song::set_lyrics(const TagLib::String &v) { d->lyrics_ = TagLibStringToQString(v); } +void Song::set_artist_id(const TagLib::String &v) { d->artist_id_ = TagLibStringToQString(v); } +void Song::set_album_id(const TagLib::String &v) { d->album_id_ = TagLibStringToQString(v); } +void Song::set_song_id(const TagLib::String &v) { d->song_id_ = TagLibStringToQString(v); } +void Song::set_acoustid_id(const TagLib::String &v) { d->acoustid_id_ = TagLibStringToQString(v); } +void Song::set_acoustid_fingerprint(const TagLib::String &v) { d->acoustid_fingerprint_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_album_artist_id(const TagLib::String &v) { d->musicbrainz_album_artist_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_artist_id(const TagLib::String &v) { d->musicbrainz_artist_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_original_artist_id(const TagLib::String &v) { d->musicbrainz_original_artist_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_album_id(const TagLib::String &v) { d->musicbrainz_album_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_original_album_id(const TagLib::String &v) { d->musicbrainz_original_album_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_recording_id(const TagLib::String &v) { d->musicbrainz_recording_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_track_id(const TagLib::String &v) { d->musicbrainz_track_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_disc_id(const TagLib::String &v) { d->musicbrainz_disc_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_release_group_id(const TagLib::String &v) { d->musicbrainz_release_group_id_ = TagLibStringToQString(v); } +void Song::set_musicbrainz_work_id(const TagLib::String &v) { d->musicbrainz_work_id_ = TagLibStringToQString(v); } + const QUrl &Song::effective_stream_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; } const QString &Song::effective_albumartist() const { return d->albumartist_.isEmpty() ? d->artist_ : d->albumartist_; } const QString &Song::effective_albumartist_sortable() const { return d->albumartist_.isEmpty() ? d->artist_sortable_ : d->albumartist_sortable_; } @@ -1312,125 +1390,6 @@ void Song::Init(const QString &title, const QString &artist, const QString &albu } -void Song::InitFromProtobuf(const spb::tagreader::SongMetadata &pb) { - - if (d->source_ == Source::Unknown) d->source_ = Source::LocalFile; - - d->init_from_file_ = true; - d->valid_ = pb.valid(); - set_title(QString::fromStdString(pb.title())); - set_album(QString::fromStdString(pb.album())); - set_artist(QString::fromStdString(pb.artist())); - set_albumartist(QString::fromStdString(pb.albumartist())); - d->track_ = pb.track(); - d->disc_ = pb.disc(); - d->year_ = pb.year(); - d->originalyear_ = pb.originalyear(); - d->genre_ = QString::fromStdString(pb.genre()); - d->compilation_ = pb.compilation(); - d->composer_ = QString::fromStdString(pb.composer()); - d->performer_ = QString::fromStdString(pb.performer()); - d->grouping_ = QString::fromStdString(pb.grouping()); - d->comment_ = QString::fromStdString(pb.comment()); - d->lyrics_ = QString::fromStdString(pb.lyrics()); - set_length_nanosec(static_cast(pb.length_nanosec())); - d->bitrate_ = pb.bitrate(); - d->samplerate_ = pb.samplerate(); - d->bitdepth_ = pb.bitdepth(); - set_url(QUrl::fromEncoded(QString::fromStdString(pb.url()).toUtf8())); - d->basefilename_ = QString::fromStdString(pb.basefilename()); - d->filetype_ = static_cast(pb.filetype()); - d->filesize_ = pb.filesize(); - d->mtime_ = pb.mtime(); - d->ctime_ = pb.ctime(); - d->skipcount_ = pb.skipcount(); - d->lastplayed_ = pb.lastplayed(); - d->lastseen_ = pb.lastseen(); - - if (pb.has_playcount()) { - d->playcount_ = pb.playcount(); - } - if (pb.has_rating()) { - d->rating_ = pb.rating(); - } - - d->art_embedded_ = pb.has_art_embedded(); - - d->acoustid_id_ = QString::fromStdString(pb.acoustid_id()); - d->acoustid_fingerprint_ = QString::fromStdString(pb.acoustid_fingerprint()); - - d->musicbrainz_album_artist_id_ = QString::fromStdString(pb.musicbrainz_album_artist_id()); - d->musicbrainz_artist_id_ = QString::fromStdString(pb.musicbrainz_artist_id().data()); - d->musicbrainz_original_artist_id_ = QString::fromStdString(pb.musicbrainz_original_artist_id()); - d->musicbrainz_album_id_ = QString::fromStdString(pb.musicbrainz_album_id()); - d->musicbrainz_original_album_id_ = QString::fromStdString(pb.musicbrainz_original_album_id()); - d->musicbrainz_recording_id_ = QString::fromStdString(pb.musicbrainz_recording_id()); - d->musicbrainz_track_id_ = QString::fromStdString(pb.musicbrainz_track_id()); - d->musicbrainz_disc_id_ = QString::fromStdString(pb.musicbrainz_disc_id()); - d->musicbrainz_release_group_id_ = QString::fromStdString(pb.musicbrainz_release_group_id()); - d->musicbrainz_work_id_ = QString::fromStdString(pb.musicbrainz_work_id()); - - d->suspicious_tags_ = pb.suspicious_tags(); - - InitArtManual(); - -} - -void Song::ToProtobuf(spb::tagreader::SongMetadata *pb) const { - - const QByteArray url(d->url_.toEncoded()); - - pb->set_valid(d->valid_); - pb->set_title(d->title_.toStdString()); - pb->set_album(d->album_.toStdString()); - pb->set_artist(d->artist_.toStdString()); - pb->set_albumartist(d->albumartist_.toStdString()); - pb->set_track(d->track_); - pb->set_disc(d->disc_); - pb->set_year(d->year_); - pb->set_originalyear(d->originalyear_); - pb->set_genre(d->genre_.toStdString()); - pb->set_compilation(d->compilation_); - pb->set_composer(d->composer_.toStdString()); - pb->set_performer(d->performer_.toStdString()); - pb->set_grouping(d->grouping_.toStdString()); - pb->set_comment(d->comment_.toStdString()); - pb->set_lyrics(d->lyrics_.toStdString()); - pb->set_length_nanosec(length_nanosec()); - pb->set_bitrate(d->bitrate_); - pb->set_samplerate(d->samplerate_); - pb->set_bitdepth(d->bitdepth_); - pb->set_url(url.constData(), url.size()); - pb->set_basefilename(d->basefilename_.toStdString()); - pb->set_filetype(static_cast(d->filetype_)); - pb->set_filesize(d->filesize_); - pb->set_mtime(d->mtime_); - pb->set_ctime(d->ctime_); - pb->set_playcount(d->playcount_); - pb->set_skipcount(d->skipcount_); - pb->set_lastplayed(d->lastplayed_); - pb->set_lastseen(d->lastseen_); - pb->set_art_embedded(d->art_embedded_); - pb->set_rating(d->rating_); - - pb->set_acoustid_id(d->acoustid_id_.toStdString()); - pb->set_acoustid_fingerprint(d->acoustid_fingerprint_.toStdString()); - - pb->set_musicbrainz_album_artist_id(d->musicbrainz_album_artist_id_.toStdString()); - pb->set_musicbrainz_artist_id(d->musicbrainz_artist_id_.toStdString()); - pb->set_musicbrainz_original_artist_id(d->musicbrainz_original_artist_id_.toStdString()); - pb->set_musicbrainz_album_id(d->musicbrainz_album_id_.toStdString()); - pb->set_musicbrainz_original_album_id(d->musicbrainz_original_album_id_.toStdString()); - pb->set_musicbrainz_recording_id(d->musicbrainz_recording_id_.toStdString()); - pb->set_musicbrainz_track_id(d->musicbrainz_track_id_.toStdString()); - pb->set_musicbrainz_disc_id(d->musicbrainz_disc_id_.toStdString()); - pb->set_musicbrainz_release_group_id(d->musicbrainz_release_group_id_.toStdString()); - pb->set_musicbrainz_work_id(d->musicbrainz_work_id_.toStdString()); - - pb->set_suspicious_tags(d->suspicious_tags_); - -} - void Song::InitFromQuery(const QSqlRecord &r, const bool reliable_metadata, const int col) { Q_ASSERT(kRowIdColumns.count() + col <= r.count()); diff --git a/src/core/song.h b/src/core/song.h index 383058aae..e21790b66 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -41,17 +41,15 @@ #include #include +#include +#undef TStringToQString +#undef QStringToTString + class SqlQuery; class QSqlRecord; class EngineMetadata; -namespace spb { -namespace tagreader { -class SongMetadata; -} // namespace tagreader -} // namespace spb - #ifdef HAVE_LIBGPOD struct _Itdb_Track; #endif @@ -81,9 +79,6 @@ class Song { Spotify = 11 }; - // Don't change these values - they're stored in the database, and defined in the tag reader protobuf. - // If a new lossless file is added, also add it to IsFileLossless(). - enum class FileType { Unknown = 0, WAV = 1, @@ -227,6 +222,29 @@ class Song { std::optional ebur128_integrated_loudness_lufs() const; std::optional ebur128_loudness_range_lu() const; + QString *mutable_title(); + QString *mutable_album(); + QString *mutable_artist(); + QString *mutable_albumartist(); + QString *mutable_genre(); + QString *mutable_composer(); + QString *mutable_performer(); + QString *mutable_grouping(); + QString *mutable_comment(); + QString *mutable_lyrics(); + QString *mutable_acoustid_id(); + QString *mutable_acoustid_fingerprint(); + QString *mutable_musicbrainz_album_artist_id(); + QString *mutable_musicbrainz_artist_id(); + QString *mutable_musicbrainz_original_artist_id(); + QString *mutable_musicbrainz_album_id(); + QString *mutable_musicbrainz_original_album_id(); + QString *mutable_musicbrainz_recording_id(); + QString *mutable_musicbrainz_track_id(); + QString *mutable_musicbrainz_disc_id(); + QString *mutable_musicbrainz_release_group_id(); + QString *mutable_musicbrainz_work_id(); + bool init_from_file() const; const QString &title_sortable() const; @@ -317,6 +335,32 @@ class Song { void set_stream_url(const QUrl &v); + void set_title(const TagLib::String &v); + void set_album(const TagLib::String &v); + void set_artist(const TagLib::String &v); + void set_albumartist(const TagLib::String &v); + void set_genre(const TagLib::String &v); + void set_composer(const TagLib::String &v); + void set_performer(const TagLib::String &v); + void set_grouping(const TagLib::String &v); + void set_comment(const TagLib::String &v); + void set_lyrics(const TagLib::String &v); + void set_artist_id(const TagLib::String &v); + void set_album_id(const TagLib::String &v); + void set_song_id(const TagLib::String &v); + void set_acoustid_id(const TagLib::String &v); + void set_acoustid_fingerprint(const TagLib::String &v); + void set_musicbrainz_album_artist_id(const TagLib::String &v); + void set_musicbrainz_artist_id(const TagLib::String &v); + void set_musicbrainz_original_artist_id(const TagLib::String &v); + void set_musicbrainz_album_id(const TagLib::String &v); + void set_musicbrainz_original_album_id(const TagLib::String &v); + void set_musicbrainz_recording_id(const TagLib::String &v); + void set_musicbrainz_track_id(const TagLib::String &v); + void set_musicbrainz_disc_id(const TagLib::String &v); + void set_musicbrainz_release_group_id(const TagLib::String &v); + void set_musicbrainz_work_id(const TagLib::String &v); + const QUrl &effective_stream_url() const; const QString &effective_albumartist() const; const QString &effective_albumartist_sortable() const; @@ -422,7 +466,6 @@ class Song { // Constructors void Init(const QString &title, const QString &artist, const QString &album, const qint64 length_nanosec); void Init(const QString &title, const QString &artist, const QString &album, const qint64 beginning, const qint64 end); - void InitFromProtobuf(const spb::tagreader::SongMetadata &pb); void InitFromQuery(const QSqlRecord &r, const bool reliable_metadata, const int col = 0); void InitFromQuery(const SqlQuery &query, const bool reliable_metadata, const int col = 0); void InitFromQuery(const SqlRow &row, const bool reliable_metadata, const int col = 0); @@ -445,7 +488,6 @@ class Song { #ifdef HAVE_DBUS void ToXesam(QVariantMap *map) const; #endif - void ToProtobuf(spb::tagreader::SongMetadata *pb) const; bool MergeFromEngineMetadata(const EngineMetadata &engine_metadata); @@ -465,6 +507,10 @@ class Song { static QString AlbumRemoveDiscMisc(const QString &album); static QString TitleRemoveMisc(const QString &title); + static inline QString TagLibStringToQString(const TagLib::String &s) { + return QString::fromUtf8((s).toCString(true)); + } + private: struct Private; diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp index f97251c12..b2b411937 100644 --- a/src/core/songloader.cpp +++ b/src/core/songloader.cpp @@ -48,10 +48,10 @@ #include "player.h" #include "song.h" #include "songloader.h" -#include "tagreaderclient.h" #include "database.h" #include "sqlrow.h" #include "engine/enginebase.h" +#include "tagreader/tagreaderclient.h" #include "collection/collectionbackend.h" #include "collection/collectionquery.h" #include "playlistparsers/cueparser.h" @@ -362,9 +362,9 @@ void SongLoader::EffectiveSongLoad(Song *song) { else { // It's a normal media file const QString filename = song->url().toLocalFile(); - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(filename, song); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(filename, song); if (!result.success()) { - qLog(Error) << "Could not read file" << song->url() << result.error; + qLog(Error) << "Could not read file" << song->url() << result.error_string(); } } diff --git a/src/core/tagreaderclient.cpp b/src/core/tagreaderclient.cpp deleted file mode 100644 index e665d8ec3..000000000 --- a/src/core/tagreaderclient.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2010, David Sansome - * Copyright 2019-2024, Jonas Kvinge - * - * Strawberry is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Strawberry is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Strawberry. If not, see . - * - */ - -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "core/logging.h" -#include "core/workerpool.h" - -#include "song.h" -#include "tagreaderclient.h" - -using namespace Qt::StringLiterals; - -namespace { -constexpr char kWorkerExecutableName[] = "strawberry-tagreader"; -} - -TagReaderClient *TagReaderClient::sInstance = nullptr; - -TagReaderClient::TagReaderClient(QObject *parent) : QObject(parent), worker_pool_(new WorkerPool(this)) { - - setObjectName(QLatin1String(metaObject()->className())); - - sInstance = this; - original_thread_ = thread(); - - worker_pool_->SetExecutableName(QLatin1String(kWorkerExecutableName)); - QObject::connect(worker_pool_, &WorkerPool::WorkerFailedToStart, this, &TagReaderClient::WorkerFailedToStart); - -} - -void TagReaderClient::Start() { worker_pool_->Start(); } - -void TagReaderClient::ExitAsync() { - QMetaObject::invokeMethod(this, &TagReaderClient::Exit, Qt::QueuedConnection); -} - -void TagReaderClient::Exit() { - - Q_ASSERT(QThread::currentThread() == thread()); - moveToThread(original_thread_); - Q_EMIT ExitFinished(); - -} - -void TagReaderClient::WorkerFailedToStart() { - qLog(Error) << "The" << kWorkerExecutableName << "executable was not found in the current directory or on the PATH. Strawberry will not be able to read music file tags without it."; -} - -TagReaderReply *TagReaderClient::IsMediaFile(const QString &filename) { - - spb::tagreader::Message message; - message.mutable_is_media_file_request()->set_filename(filename.toStdString()); - return worker_pool_->SendMessageWithReply(&message); - -} - -TagReaderReply *TagReaderClient::ReadFile(const QString &filename) { - - spb::tagreader::Message message; - message.mutable_read_file_request()->set_filename(filename.toStdString()); - return worker_pool_->SendMessageWithReply(&message); - -} - -TagReaderReply *TagReaderClient::WriteFile(const QString &filename, const Song &metadata, const SaveTypes save_types, const SaveCoverOptions &save_cover_options) { - - spb::tagreader::Message message; - spb::tagreader::WriteFileRequest *request = message.mutable_write_file_request(); - - request->set_filename(filename.toStdString()); - - request->set_save_tags(save_types.testFlag(SaveType::Tags)); - request->set_save_playcount(save_types.testFlag(SaveType::PlayCount)); - request->set_save_rating(save_types.testFlag(SaveType::Rating)); - request->set_save_cover(save_types.testFlag(SaveType::Cover)); - - if (!save_cover_options.cover_filename.isEmpty()) { - request->set_cover_filename(save_cover_options.cover_filename.toStdString()); - } - if (!save_cover_options.cover_data.isEmpty()) { - request->set_cover_data(save_cover_options.cover_data.toStdString()); - } - if (!save_cover_options.mime_type.isEmpty()) { - request->set_cover_mime_type(save_cover_options.mime_type.toStdString()); - } - - metadata.ToProtobuf(request->mutable_metadata()); - - ReplyType *reply = worker_pool_->SendMessageWithReply(&message); - - return reply; - -} - -TagReaderReply *TagReaderClient::LoadEmbeddedArt(const QString &filename) { - - spb::tagreader::Message message; - spb::tagreader::LoadEmbeddedArtRequest *request = message.mutable_load_embedded_art_request(); - - request->set_filename(filename.toStdString()); - - return worker_pool_->SendMessageWithReply(&message); - -} - -TagReaderReply *TagReaderClient::SaveEmbeddedArt(const QString &filename, const SaveCoverOptions &save_cover_options) { - - spb::tagreader::Message message; - spb::tagreader::SaveEmbeddedArtRequest *request = message.mutable_save_embedded_art_request(); - - request->set_filename(filename.toStdString()); - - if (!save_cover_options.cover_filename.isEmpty()) { - request->set_cover_filename(save_cover_options.cover_filename.toStdString()); - } - if (!save_cover_options.cover_data.isEmpty()) { - request->set_cover_data(save_cover_options.cover_data.toStdString()); - } - if (!save_cover_options.mime_type.isEmpty()) { - request->set_cover_mime_type(save_cover_options.mime_type.toStdString()); - } - - return worker_pool_->SendMessageWithReply(&message); - -} - -TagReaderReply *TagReaderClient::SaveSongPlaycount(const QString &filename, const uint playcount) { - - spb::tagreader::Message message; - spb::tagreader::SaveSongPlaycountToFileRequest *request = message.mutable_save_song_playcount_to_file_request(); - - request->set_filename(filename.toStdString()); - request->set_playcount(playcount); - - return worker_pool_->SendMessageWithReply(&message); - -} - -void TagReaderClient::SaveSongsPlaycount(const SongList &songs) { - - for (const Song &song : songs) { - TagReaderReply *reply = SaveSongPlaycount(song.url().toLocalFile(), song.playcount()); - QObject::connect(reply, &TagReaderReply::Finished, reply, &TagReaderReply::deleteLater); - } - -} - -TagReaderReply *TagReaderClient::SaveSongRating(const QString &filename, const float rating) { - - spb::tagreader::Message message; - spb::tagreader::SaveSongRatingToFileRequest *request = message.mutable_save_song_rating_to_file_request(); - - request->set_filename(filename.toStdString()); - request->set_rating(rating); - - return worker_pool_->SendMessageWithReply(&message); - -} - -void TagReaderClient::SaveSongsRating(const SongList &songs) { - - for (const Song &song : songs) { - TagReaderReply *reply = SaveSongRating(song.url().toLocalFile(), song.rating()); - QObject::connect(reply, &TagReaderReply::Finished, reply, &TagReaderReply::deleteLater); - } - -} - -bool TagReaderClient::IsMediaFileBlocking(const QString &filename) { - - Q_ASSERT(QThread::currentThread() != thread()); - - bool success = false; - - TagReaderReply *reply = IsMediaFile(filename); - if (reply->WaitForFinished()) { - const spb::tagreader::IsMediaFileResponse &response = reply->message().is_media_file_response(); - if (response.has_success()) { - success = response.success(); - } - } - reply->deleteLater(); - - return success; - -} - -TagReaderClient::Result TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = ReadFile(filename); - if (reply->WaitForFinished()) { - const spb::tagreader::ReadFileResponse &response = reply->message().read_file_response(); - if (response.has_success()) { - if (response.success()) { - result.error_code = Result::ErrorCode::Success; - if (response.has_metadata()) { - song->InitFromProtobuf(response.metadata()); - } - } - else { - result.error_code = Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - } - reply->deleteLater(); - - return result; - -} - -TagReaderClient::Result TagReaderClient::WriteFileBlocking(const QString &filename, const Song &metadata, const SaveTypes save_types, const SaveCoverOptions &save_cover_options) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = WriteFile(filename, metadata, save_types, save_cover_options); - if (reply->WaitForFinished()) { - const spb::tagreader::WriteFileResponse &response = reply->message().write_file_response(); - if (response.has_success()) { - result.error_code = response.success() ? Result::ErrorCode::Success : Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - reply->deleteLater(); - - return result; - -} - -TagReaderClient::Result TagReaderClient::LoadEmbeddedArtBlocking(const QString &filename, QByteArray &data) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = LoadEmbeddedArt(filename); - if (reply->WaitForFinished()) { - const spb::tagreader::LoadEmbeddedArtResponse &response = reply->message().load_embedded_art_response(); - if (response.has_success()) { - if (response.success()) { - result.error_code = Result::ErrorCode::Success; - if (response.has_data()) { - data = QByteArray(response.data().data(), static_cast(response.data().size())); - } - } - else { - result.error_code = Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - } - reply->deleteLater(); - - return result; - -} - -TagReaderClient::Result TagReaderClient::LoadEmbeddedArtAsImageBlocking(const QString &filename, QImage &image) { - - Q_ASSERT(QThread::currentThread() != thread()); - - QByteArray data; - Result result = LoadEmbeddedArtBlocking(filename, data); - if (result.error_code == Result::ErrorCode::Success && !image.loadFromData(data)) { - result.error_code = Result::ErrorCode::Failure; - result.error = QObject::tr("Failed to load image from data for %1").arg(filename); - } - - return result; - -} - -TagReaderClient::Result TagReaderClient::SaveEmbeddedArtBlocking(const QString &filename, const SaveCoverOptions &save_cover_options) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = SaveEmbeddedArt(filename, save_cover_options); - if (reply->WaitForFinished()) { - const spb::tagreader::SaveEmbeddedArtResponse &response = reply->message().save_embedded_art_response(); - if (response.has_success()) { - result.error_code = response.success() ? Result::ErrorCode::Success : Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - reply->deleteLater(); - - return result; - -} - -TagReaderClient::Result TagReaderClient::SaveSongPlaycountBlocking(const QString &filename, const uint playcount) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = SaveSongPlaycount(filename, playcount); - if (reply->WaitForFinished()) { - const spb::tagreader::SaveSongPlaycountToFileResponse &response = reply->message().save_song_playcount_to_file_response(); - if (response.has_success()) { - result.error_code = response.success() ? Result::ErrorCode::Success : Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - reply->deleteLater(); - - return result; - -} - -TagReaderClient::Result TagReaderClient::SaveSongRatingBlocking(const QString &filename, const float rating) { - - Q_ASSERT(QThread::currentThread() != thread()); - - Result result(Result::ErrorCode::Failure); - - TagReaderReply *reply = SaveSongRating(filename, rating); - if (reply->WaitForFinished()) { - const spb::tagreader::SaveSongRatingToFileResponse &response = reply->message().save_song_rating_to_file_response(); - if (response.has_success()) { - result.error_code = response.success() ? Result::ErrorCode::Success : Result::ErrorCode::Failure; - if (response.has_error()) { - result.error = QString::fromStdString(response.error()); - } - } - } - reply->deleteLater(); - - return result; - -} diff --git a/src/core/tagreaderclient.h b/src/core/tagreaderclient.h deleted file mode 100644 index 7bd75eabf..000000000 --- a/src/core/tagreaderclient.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2011, David Sansome - * Copyright 2019-2024, Jonas Kvinge - * - * Strawberry is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Strawberry is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Strawberry. If not, see . - * - */ - -#ifndef TAGREADERCLIENT_H -#define TAGREADERCLIENT_H - -#include "config.h" - -#include -#include -#include -#include - -#include "core/messagehandler.h" -#include "core/workerpool.h" - -#include "song.h" -#include "tagreadermessages.pb.h" - -class QThread; -class Song; -template class WorkerPool; - -class TagReaderClient : public QObject { - Q_OBJECT - - public: - explicit TagReaderClient(QObject *parent = nullptr); - - using HandlerType = AbstractMessageHandler; - using ReplyType = HandlerType::ReplyType; - - void Start(); - void ExitAsync(); - - enum class SaveType { - NoType = 0, - Tags = 1, - PlayCount = 2, - Rating = 4, - Cover = 8 - }; - Q_DECLARE_FLAGS(SaveTypes, SaveType) - - class SaveCoverOptions { - public: - explicit SaveCoverOptions(const QString &_cover_filename = QString(), const QByteArray &_cover_data = QByteArray(), const QString &_mime_type = QString()) : cover_filename(_cover_filename), cover_data(_cover_data), mime_type(_mime_type) {} - explicit SaveCoverOptions(const QString &_cover_filename, const QString &_mime_type = QString()) : cover_filename(_cover_filename), mime_type(_mime_type) {} - explicit SaveCoverOptions(const QByteArray &_cover_data, const QString &_mime_type = QString()) : cover_data(_cover_data), mime_type(_mime_type) {} - QString cover_filename; - QByteArray cover_data; - QString mime_type; - }; - - class Result { - public: - enum class ErrorCode { - Success, - Unsupported, - Failure, - }; - Result(const ErrorCode _error_code, const QString &_error = QString()) : error_code(_error_code), error(_error) {} - ErrorCode error_code; - QString error; - bool success() const { return error_code == TagReaderClient::Result::ErrorCode::Success; } - }; - - class Cover { - public: - explicit Cover(const QByteArray &_data = QByteArray(), const QString &_mime_type = QString()) : data(_data), mime_type(_mime_type) {} - QByteArray data; - QString mime_type; - QString error; - }; - - ReplyType *IsMediaFile(const QString &filename); - ReplyType *ReadFile(const QString &filename); - ReplyType *WriteFile(const QString &filename, const Song &metadata, const SaveTypes types = SaveType::Tags, const SaveCoverOptions &save_cover_options = SaveCoverOptions()); - ReplyType *LoadEmbeddedArt(const QString &filename); - ReplyType *SaveEmbeddedArt(const QString &filename, const SaveCoverOptions &save_cover_options); - ReplyType *SaveSongPlaycount(const QString &filename, const uint playcount); - ReplyType *SaveSongRating(const QString &filename, const float rating); - - // Convenience functions that call the above functions and wait for a response. - // These block the calling thread with a semaphore, and must NOT be called from the TagReaderClient's thread. - Result ReadFileBlocking(const QString &filename, Song *song); - Result WriteFileBlocking(const QString &filename, const Song &metadata, const SaveTypes types = SaveType::Tags, const SaveCoverOptions &save_cover_options = SaveCoverOptions()); - bool IsMediaFileBlocking(const QString &filename); - Result LoadEmbeddedArtBlocking(const QString &filename, QByteArray &data); - Result LoadEmbeddedArtAsImageBlocking(const QString &filename, QImage &image); - Result SaveEmbeddedArtBlocking(const QString &filename, const SaveCoverOptions &save_cover_options); - Result SaveSongPlaycountBlocking(const QString &filename, const uint playcount); - Result SaveSongRatingBlocking(const QString &filename, const float rating); - - // TODO: Make this not a singleton - static TagReaderClient *Instance() { return sInstance; } - - Q_SIGNALS: - void ExitFinished(); - - private Q_SLOTS: - void Exit(); - void WorkerFailedToStart(); - - public Q_SLOTS: - void SaveSongsPlaycount(const SongList &songs); - void SaveSongsRating(const SongList &songs); - - private: - static TagReaderClient *sInstance; - - WorkerPool *worker_pool_; - QList message_queue_; - QThread *original_thread_; -}; - -using TagReaderReply = TagReaderClient::ReplyType; - -#endif // TAGREADERCLIENT_H diff --git a/src/covermanager/albumcoverchoicecontroller.cpp b/src/covermanager/albumcoverchoicecontroller.cpp index d6d406bc1..b3c9a6290 100644 --- a/src/covermanager/albumcoverchoicecontroller.cpp +++ b/src/covermanager/albumcoverchoicecontroller.cpp @@ -63,9 +63,8 @@ #include "core/application.h" #include "core/song.h" #include "core/iconloader.h" -#include "core/tagreaderclient.h" #include "core/settings.h" - +#include "tagreader/tagreaderclient.h" #include "collection/collectionfilteroptions.h" #include "collection/collectionbackend.h" #include "settings/coverssettingspage.h" @@ -447,7 +446,7 @@ void AlbumCoverChoiceController::ShowCover(const Song &song, const QImage &image case AlbumCoverLoaderOptions::Type::Embedded:{ if (song.art_embedded() && !song.url().isEmpty() && song.url().isValid() && song.url().isLocalFile()) { QImage image_embedded_cover; - const TagReaderClient::Result result = TagReaderClient::Instance()->LoadEmbeddedArtAsImageBlocking(song.url().toLocalFile(), image_embedded_cover); + const TagReaderResult result = TagReaderClient::Instance()->LoadCoverImageBlocking(song.url().toLocalFile(), image_embedded_cover); if (result.success() && !image_embedded_cover.isNull()) { QPixmap pixmap = QPixmap::fromImage(image_embedded_cover); if (!pixmap.isNull()) { @@ -737,8 +736,8 @@ void AlbumCoverChoiceController::SaveCoverEmbeddedToSong(const Song &song, const QMutexLocker l(&mutex_cover_save_tasks_); cover_save_tasks_.append(song); const bool art_embedded = !image_data.isNull(); - TagReaderReply *reply = app_->tag_reader_client()->SaveEmbeddedArt(song.url().toLocalFile(), TagReaderClient::SaveCoverOptions(cover_filename, image_data, mime_type)); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, song, art_embedded]() { SaveEmbeddedCoverFinished(reply, song, art_embedded); }); + TagReaderReplyPtr reply = app_->tag_reader_client()->SaveCoverAsync(song.url().toLocalFile(), SaveTagCoverData(cover_filename, image_data, mime_type)); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, song, art_embedded]() { SaveEmbeddedCoverFinished(reply, song, art_embedded); }); } @@ -815,12 +814,12 @@ QUrl AlbumCoverChoiceController::SaveCoverAutomatic(Song *song, const AlbumCover } -void AlbumCoverChoiceController::SaveEmbeddedCoverFinished(TagReaderReply *reply, Song song, const bool art_embedded) { +void AlbumCoverChoiceController::SaveEmbeddedCoverFinished(TagReaderReplyPtr reply, Song song, const bool art_embedded) { if (!cover_save_tasks_.contains(song)) return; cover_save_tasks_.removeAll(song); - if (reply->is_successful()) { + if (reply->success()) { SaveArtEmbeddedToSong(&song, art_embedded); } else { diff --git a/src/covermanager/albumcoverchoicecontroller.h b/src/covermanager/albumcoverchoicecontroller.h index 6936be7f8..6132e2173 100644 --- a/src/covermanager/albumcoverchoicecontroller.h +++ b/src/covermanager/albumcoverchoicecontroller.h @@ -38,7 +38,7 @@ #include #include "core/song.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "utilities/coveroptions.h" #include "albumcoverloaderoptions.h" #include "albumcoverimageresult.h" @@ -160,7 +160,7 @@ class AlbumCoverChoiceController : public QWidget { private Q_SLOTS: void AlbumCoverFetched(const quint64 id, const AlbumCoverImageResult &result, const CoverSearchStatistics &statistics); - void SaveEmbeddedCoverFinished(TagReaderReply *reply, Song song, const bool art_embedded); + void SaveEmbeddedCoverFinished(TagReaderReplyPtr reply, Song song, const bool art_embedded); Q_SIGNALS: void Error(const QString &error); diff --git a/src/covermanager/albumcoverloader.cpp b/src/covermanager/albumcoverloader.cpp index b52f341cc..6d016ac08 100644 --- a/src/covermanager/albumcoverloader.cpp +++ b/src/covermanager/albumcoverloader.cpp @@ -39,9 +39,9 @@ #include "core/logging.h" #include "core/networkaccessmanager.h" #include "core/song.h" -#include "core/tagreaderclient.h" #include "utilities/mimeutils.h" #include "utilities/imageutils.h" +#include "tagreader/tagreaderclient.h" #include "albumcoverloader.h" #include "albumcoverloaderoptions.h" #include "albumcoverloaderresult.h" @@ -318,7 +318,7 @@ AlbumCoverLoader::LoadImageResult AlbumCoverLoader::LoadImage(TaskPtr task, cons AlbumCoverLoader::LoadImageResult AlbumCoverLoader::LoadEmbeddedImage(TaskPtr task) { if (task->art_embedded && task->song_url.isValid() && task->song_url.isLocalFile()) { - const TagReaderClient::Result result = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(task->song_url.toLocalFile(), task->album_cover.image_data); + const TagReaderResult result = TagReaderClient::Instance()->LoadCoverDataBlocking(task->song_url.toLocalFile(), task->album_cover.image_data); if (result.success() && !task->album_cover.image_data.isEmpty() && task->album_cover.image.loadFromData(task->album_cover.image_data)) { return LoadImageResult(AlbumCoverLoaderResult::Type::Embedded, LoadImageResult::Status::Success); } diff --git a/src/covermanager/albumcovermanager.cpp b/src/covermanager/albumcovermanager.cpp index 801f1f723..dfdd3f497 100644 --- a/src/covermanager/albumcovermanager.cpp +++ b/src/covermanager/albumcovermanager.cpp @@ -66,7 +66,6 @@ #include "core/logging.h" #include "core/application.h" #include "core/iconloader.h" -#include "core/tagreaderclient.h" #include "core/database.h" #include "core/sqlrow.h" #include "core/settings.h" @@ -77,6 +76,7 @@ #include "utilities/screenutils.h" #include "widgets/forcescrollperpixel.h" #include "widgets/searchfield.h" +#include "tagreader/tagreaderclient.h" #include "collection/collectionbackend.h" #include "collection/collectionquery.h" #include "playlist/songmimedata.h" @@ -758,9 +758,9 @@ void AlbumCoverManager::SaveCoverToFile() { return; case AlbumCoverLoaderOptions::Type::Embedded: if (song.art_embedded()) { - const TagReaderClient::Result tagreaderclient_result = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(song.url().toLocalFile(), result.image_data); + const TagReaderResult tagreaderclient_result = TagReaderClient::Instance()->LoadCoverDataBlocking(song.url().toLocalFile(), result.image_data); if (!tagreaderclient_result.success()) { - qLog(Error) << "Could not load embedded art from" << song.url() << tagreaderclient_result.error; + qLog(Error) << "Could not load embedded art from" << song.url() << tagreaderclient_result.error_string(); } } break; @@ -845,8 +845,8 @@ void AlbumCoverManager::SaveImageToAlbums(Song *song, const AlbumCoverImageResul case CoverOptions::CoverType::Embedded:{ for (const QUrl &url : std::as_const(album_item->urls)) { const bool art_embedded = !result.image_data.isEmpty(); - TagReaderReply *reply = app_->tag_reader_client()->SaveEmbeddedArt(url.toLocalFile(), TagReaderClient::SaveCoverOptions(result.image_data, result.mime_type)); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, album_item, url, art_embedded]() { + TagReaderReplyPtr reply = app_->tag_reader_client()->SaveCoverAsync(url.toLocalFile(), SaveTagCoverData(result.image_data, result.mime_type)); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, album_item, url, art_embedded]() { SaveEmbeddedCoverFinished(reply, album_item, url, art_embedded); }); cover_save_tasks_.insert(album_item, url); @@ -995,8 +995,8 @@ void AlbumCoverManager::SaveAndSetCover(AlbumItem *album_item, const AlbumCoverI if (album_cover_choice_controller_->get_save_album_cover_type() == CoverOptions::CoverType::Embedded && Song::save_embedded_cover_supported(filetype) && !has_cue) { for (const QUrl &url : urls) { const bool art_embedded = !result.image_data.isEmpty(); - TagReaderReply *reply = app_->tag_reader_client()->SaveEmbeddedArt(url.toLocalFile(), TagReaderClient::SaveCoverOptions(result.cover_url.isValid() ? result.cover_url.toLocalFile() : QString(), result.image_data, result.mime_type)); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, album_item, url, art_embedded]() { + TagReaderReplyPtr reply = app_->tag_reader_client()->SaveCoverAsync(url.toLocalFile(), SaveTagCoverData(result.cover_url.isValid() ? result.cover_url.toLocalFile() : QString(), result.image_data, result.mime_type)); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, album_item, url, art_embedded]() { SaveEmbeddedCoverFinished(reply, album_item, url, art_embedded); }); cover_save_tasks_.insert(album_item, url); @@ -1094,13 +1094,13 @@ bool AlbumCoverManager::ItemHasCover(const AlbumItem &album_item) const { return album_item.icon().cacheKey() != icon_nocover_item_.cacheKey(); } -void AlbumCoverManager::SaveEmbeddedCoverFinished(TagReaderReply *reply, AlbumItem *album_item, const QUrl &url, const bool art_embedded) { +void AlbumCoverManager::SaveEmbeddedCoverFinished(TagReaderReplyPtr reply, AlbumItem *album_item, const QUrl &url, const bool art_embedded) { if (cover_save_tasks_.contains(album_item, url)) { cover_save_tasks_.remove(album_item, url); } - if (!reply->is_successful()) { + if (!reply->success()) { Q_EMIT Error(tr("Could not save cover to file %1.").arg(url.toLocalFile())); return; } diff --git a/src/covermanager/albumcovermanager.h b/src/covermanager/albumcovermanager.h index 5b2515e2a..a29a5b86a 100644 --- a/src/covermanager/albumcovermanager.h +++ b/src/covermanager/albumcovermanager.h @@ -39,7 +39,7 @@ #include "core/shared_ptr.h" #include "core/song.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "albumcoverloaderoptions.h" #include "albumcoverloaderresult.h" #include "albumcoverchoicecontroller.h" @@ -185,7 +185,7 @@ class AlbumCoverManager : public QMainWindow { void UpdateCoverInList(AlbumItem *album_item, const QUrl &cover); void UpdateExportStatus(const int exported, const int skipped, const int max); - void SaveEmbeddedCoverFinished(TagReaderReply *reply, AlbumItem *album_item, const QUrl &url, const bool art_embedded); + void SaveEmbeddedCoverFinished(TagReaderReplyPtr reply, AlbumItem *album_item, const QUrl &url, const bool art_embedded); private: Ui_CoverManager *ui_; diff --git a/src/covermanager/coverexportrunnable.cpp b/src/covermanager/coverexportrunnable.cpp index bfb6f4b43..792abf1e2 100644 --- a/src/covermanager/coverexportrunnable.cpp +++ b/src/covermanager/coverexportrunnable.cpp @@ -29,7 +29,7 @@ #include #include "core/song.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "albumcoverloaderoptions.h" #include "albumcoverexport.h" #include "coverexportrunnable.h" @@ -78,7 +78,7 @@ void CoverExportRunnable::ProcessAndExportCover() { break; case AlbumCoverLoaderOptions::Type::Embedded: if (song_.art_embedded() && dialog_result_.export_embedded_) { - const TagReaderClient::Result result = TagReaderClient::Instance()->LoadEmbeddedArtAsImageBlocking(song_.url().toLocalFile(), image); + const TagReaderResult result = TagReaderClient::Instance()->LoadCoverImageBlocking(song_.url().toLocalFile(), image); if (result.success() && !image.isNull()) { extension = "jpg"_L1; } @@ -170,7 +170,7 @@ void CoverExportRunnable::ExportCover() { break; case AlbumCoverLoaderOptions::Type::Embedded: if (song_.art_embedded() && dialog_result_.export_embedded_) { - const TagReaderClient::Result result = TagReaderClient::Instance()->LoadEmbeddedArtAsImageBlocking(song_.url().toLocalFile(), image); + const TagReaderResult result = TagReaderClient::Instance()->LoadCoverImageBlocking(song_.url().toLocalFile(), image); if (result.success() && !image.isNull()) { embedded_cover = true; extension = "jpg"_L1; diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index 10db15b27..a066662d2 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -73,13 +73,13 @@ #include "core/application.h" #include "core/iconloader.h" #include "core/logging.h" -#include "core/tagreaderclient.h" #include "core/settings.h" #include "utilities/strutils.h" #include "utilities/timeutils.h" #include "utilities/imageutils.h" #include "utilities/coverutils.h" #include "utilities/coveroptions.h" +#include "tagreader/tagreaderclient.h" #include "widgets/busyindicator.h" #include "widgets/lineedit.h" #include "collection/collectionbackend.h" @@ -99,7 +99,6 @@ #include "covermanager/albumcoverimageresult.h" #include "edittagdialog.h" #include "ui_edittagdialog.h" -#include "tagreadermessages.pb.h" using namespace Qt::StringLiterals; @@ -401,7 +400,7 @@ QList EditTagDialog::LoadData(const SongList &songs) { if (song.IsEditable()) { // Try reloading the tags from file Song copy(song); - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(copy.url().toLocalFile(), ©); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(copy.url().toLocalFile(), ©); if (result.success() && copy.is_valid()) { copy.MergeUserSetData(song, false, false); ret << Data(copy); @@ -1276,31 +1275,31 @@ void EditTagDialog::SaveData() { if (ref.current_.originalyear() <= 0) { ref.current_.set_originalyear(-1); } if (ref.current_.lastplayed() <= 0) { ref.current_.set_lastplayed(-1); } ++save_tag_pending_; - TagReaderClient::SaveCoverOptions savecover_options; + SaveTagCoverData save_tag_cover_data; if (save_embedded_cover && ref.cover_action_ == UpdateCoverAction::New) { if (!ref.cover_result_.image.isNull()) { - savecover_options.mime_type = ref.cover_result_.mime_type; + save_tag_cover_data.cover_mimetype = ref.cover_result_.mime_type; } else if (!embedded_cover_from_file.isEmpty()) { - savecover_options.cover_filename = embedded_cover_from_file; + save_tag_cover_data.cover_filename = embedded_cover_from_file; } - savecover_options.cover_data = ref.cover_result_.image_data; + save_tag_cover_data.cover_data = ref.cover_result_.image_data; } - TagReaderClient::SaveTypes save_types; + TagReaderClient::SaveOptions save_tags_options; if (save_tags) { - save_types |= TagReaderClient::SaveType::Tags; + save_tags_options |= TagReaderClient::SaveOption::Tags; } if (save_playcount) { - save_types |= TagReaderClient::SaveType::PlayCount; + save_tags_options |= TagReaderClient::SaveOption::Playcount; } if (save_rating) { - save_types |= TagReaderClient::SaveType::Rating; + save_tags_options |= TagReaderClient::SaveOption::Rating; } if (save_embedded_cover) { - save_types |= TagReaderClient::SaveType::Cover; + save_tags_options |= TagReaderClient::SaveOption::Cover; } - TagReaderReply *reply = TagReaderClient::Instance()->WriteFile(ref.current_.url().toLocalFile(), ref.current_, save_types, savecover_options); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, ref]() { SongSaveTagsComplete(reply, ref.current_.url().toLocalFile(), ref.current_, ref.cover_action_); }, Qt::QueuedConnection); + TagReaderReplyPtr reply = TagReaderClient::Instance()->WriteFileAsync(ref.current_.url().toLocalFile(), ref.current_, save_tags_options, save_tag_cover_data); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, ref]() { SongSaveTagsComplete(reply, ref.current_.url().toLocalFile(), ref.current_, ref.cover_action_); }, Qt::QueuedConnection); } // If the cover was changed, but no tags written, make sure to update the collection. else if (ref.cover_action_ != UpdateCoverAction::None && !ref.current_.effective_albumartist().isEmpty() && !ref.current_.album().isEmpty()) { @@ -1451,15 +1450,12 @@ void EditTagDialog::UpdateLyrics(const quint64 id, const QString &provider, cons } -void EditTagDialog::SongSaveTagsComplete(TagReaderReply *reply, const QString &filename, Song song, const UpdateCoverAction cover_action) { +void EditTagDialog::SongSaveTagsComplete(TagReaderReplyPtr reply, const QString &filename, Song song, const UpdateCoverAction cover_action) { --save_tag_pending_; - const bool success = reply->message().write_file_response().success(); - QString error; - if (!success && reply->message().write_file_response().has_error()) { - error = QString::fromStdString(reply->message().write_file_response().error()); - } - reply->deleteLater(); + + const bool success = reply->success(); + const QString error = reply->error(); if (success) { if (song.is_collection_song()) { diff --git a/src/dialogs/edittagdialog.h b/src/dialogs/edittagdialog.h index 9e78a8e5d..731a1b65e 100644 --- a/src/dialogs/edittagdialog.h +++ b/src/dialogs/edittagdialog.h @@ -36,7 +36,7 @@ #include #include "core/song.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "playlist/playlistitem.h" #include "covermanager/albumcoverloaderoptions.h" #include "covermanager/albumcoverloaderresult.h" @@ -133,7 +133,7 @@ class EditTagDialog : public QDialog { void PreviousSong(); void NextSong(); - void SongSaveTagsComplete(TagReaderReply *reply, const QString &filename, Song song, const UpdateCoverAction cover_action); + void SongSaveTagsComplete(TagReaderReplyPtr reply, const QString &filename, Song song, const UpdateCoverAction cover_action); private: struct FieldData { diff --git a/src/dialogs/trackselectiondialog.cpp b/src/dialogs/trackselectiondialog.cpp index 6b36c994d..2e29f0dac 100644 --- a/src/dialogs/trackselectiondialog.cpp +++ b/src/dialogs/trackselectiondialog.cpp @@ -48,7 +48,7 @@ #include "core/iconloader.h" #include "core/logging.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "widgets/busyindicator.h" #include "trackselectiondialog.h" #include "ui_trackselectiondialog.h" @@ -278,9 +278,9 @@ void TrackSelectionDialog::SaveData(const QList &data) { copy.set_track(new_metadata.track()); copy.set_year(new_metadata.year()); - const TagReaderClient::Result result = TagReaderClient::Instance()->WriteFileBlocking(copy.url().toLocalFile(), copy, TagReaderClient::SaveType::Tags, TagReaderClient::SaveCoverOptions()); + const TagReaderResult result = TagReaderClient::Instance()->WriteFileBlocking(copy.url().toLocalFile(), copy, TagReaderClient::SaveOption::Tags, SaveTagCoverData()); if (!result.success()) { - qLog(Error) << "Failed to write new auto-tags to" << copy.url().toLocalFile() << result.error; + qLog(Error) << "Failed to write new auto-tags to" << copy.url().toLocalFile() << result.error_string(); } } diff --git a/src/organize/organize.cpp b/src/organize/organize.cpp index 4f700b805..5c0838fed 100644 --- a/src/organize/organize.cpp +++ b/src/organize/organize.cpp @@ -39,9 +39,9 @@ #include "core/shared_ptr.h" #include "core/taskmanager.h" #include "core/musicstorage.h" -#include "core/tagreaderclient.h" #include "core/song.h" #include "utilities/strutils.h" +#include "tagreader/tagreaderclient.h" #include "organize.h" #ifdef HAVE_GSTREAMER # include "transcoder/transcoder.h" @@ -245,9 +245,9 @@ void Organize::ProcessSomeFiles() { } } else if (destination_->source() == Song::Source::Device) { - const TagReaderClient::Result result = TagReaderClient::Instance()->LoadEmbeddedArtAsImageBlocking(task.song_info_.song_.url().toLocalFile(), job.cover_image_); + const TagReaderResult result = TagReaderClient::Instance()->LoadCoverImageBlocking(task.song_info_.song_.url().toLocalFile(), job.cover_image_); if (!result.success()) { - qLog(Error) << "Could not load embedded art from" << task.song_info_.song_.url() << result.error; + qLog(Error) << "Could not load embedded art from" << task.song_info_.song_.url() << result.error_string(); } } diff --git a/src/organize/organizedialog.cpp b/src/organize/organizedialog.cpp index 0daaf76dd..e9ae46432 100644 --- a/src/organize/organizedialog.cpp +++ b/src/organize/organizedialog.cpp @@ -59,12 +59,12 @@ #include "core/shared_ptr.h" #include "core/iconloader.h" #include "core/musicstorage.h" -#include "core/tagreaderclient.h" #include "core/settings.h" #include "utilities/strutils.h" #include "utilities/screenutils.h" #include "widgets/freespacebar.h" #include "widgets/linetextedit.h" +#include "tagreader/tagreaderclient.h" #include "collection/collectionbackend.h" #include "organize.h" #include "organizeformat.h" @@ -423,12 +423,12 @@ SongList OrganizeDialog::LoadSongsBlocking(const QStringList &filenames) { continue; } - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(filename, &song); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(filename, &song); if (result.success() && song.is_valid()) { songs << song; } else { - qLog(Error) << "Could not read file" << filename << result.error; + qLog(Error) << "Could not read file" << filename << result.error_string(); } } diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index cc2bdeaa8..e769b9e7a 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -62,10 +62,10 @@ #include "core/application.h" #include "core/logging.h" #include "core/mimedata.h" -#include "core/tagreaderclient.h" #include "core/song.h" #include "core/settings.h" #include "utilities/timeconstants.h" +#include "tagreader/tagreaderclient.h" #include "collection/collection.h" #include "collection/collectionbackend.h" #include "collection/collectionplaylistitem.h" @@ -418,9 +418,9 @@ bool Playlist::setData(const QModelIndex &idx, const QVariant &value, const int if (!set_column_value(song, static_cast(idx.column()), value)) return false; if (song.url().isLocalFile()) { - TagReaderReply *reply = TagReaderClient::Instance()->WriteFile(song.url().toLocalFile(), song); + TagReaderReplyPtr reply = TagReaderClient::Instance()->WriteFileAsync(song.url().toLocalFile(), song); QPersistentModelIndex persistent_index = QPersistentModelIndex(idx); - QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index, item]() { SongSaveComplete(reply, persistent_index, item->OriginalMetadata()); }, Qt::QueuedConnection); + QObject::connect(&*reply, &TagReaderReply::Finished, this, [this, reply, persistent_index, item]() { SongSaveComplete(reply, persistent_index, item->OriginalMetadata()); }, Qt::QueuedConnection); } else if (song.is_radio()) { item->SetMetadata(song); @@ -431,18 +431,18 @@ bool Playlist::setData(const QModelIndex &idx, const QVariant &value, const int } -void Playlist::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx, const Song &old_metadata) { +void Playlist::SongSaveComplete(TagReaderReplyPtr reply, const QPersistentModelIndex &idx, const Song &old_metadata) { - if (reply->is_successful() && idx.isValid()) { - if (reply->message().write_file_response().success()) { + if (reply->success() && idx.isValid()) { + if (reply->success()) { ItemReload(idx, old_metadata, true); } else { - if (reply->request_message().write_file_response().has_error()) { - Q_EMIT Error(tr("Could not write metadata to %1: %2").arg(QString::fromStdString(reply->request_message().write_file_request().filename()), QString::fromStdString(reply->request_message().write_file_response().error()))); + if (reply->error().isEmpty()) { + Q_EMIT Error(tr("Could not write metadata to %1").arg(reply->filename())); } else { - Q_EMIT Error(tr("Could not write metadata to %1").arg(QString::fromStdString(reply->request_message().write_file_request().filename()))); + Q_EMIT Error(tr("Could not write metadata to %1: %2").arg(reply->filename(), reply->error())); } } } diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 8595a6754..17161fc2e 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -43,7 +43,7 @@ #include "core/shared_ptr.h" #include "core/song.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "covermanager/albumcoverloaderresult.h" #include "playlistitem.h" #include "playlistsequence.h" @@ -350,7 +350,7 @@ class Playlist : public QAbstractListModel { void TracksDequeued(); void TracksEnqueued(const QModelIndex &parent_idx, const int begin, const int end); void QueueLayoutChanged(); - void SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx, const Song &old_metadata); + void SongSaveComplete(TagReaderReplyPtr reply, const QPersistentModelIndex &idx, const Song &old_metadata); void ItemReloadComplete(const QPersistentModelIndex &idx, const Song &old_metadata, const bool metadata_edit); void ItemsLoaded(); void ScheduleSave(); diff --git a/src/playlist/songplaylistitem.cpp b/src/playlist/songplaylistitem.cpp index e1c587473..f8adc0ffc 100644 --- a/src/playlist/songplaylistitem.cpp +++ b/src/playlist/songplaylistitem.cpp @@ -26,7 +26,7 @@ #include "core/logging.h" #include "core/song.h" #include "core/sqlrow.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "playlistitem.h" #include "songplaylistitem.h" @@ -44,9 +44,9 @@ void SongPlaylistItem::Reload() { if (!song_.url().isLocalFile()) return; - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); if (!result.success()) { - qLog(Error) << "Could not reload file" << song_.url() << result.error; + qLog(Error) << "Could not reload file" << song_.url() << result.error_string(); } UpdateTemporaryMetadata(song_); diff --git a/src/playlistparsers/parserbase.cpp b/src/playlistparsers/parserbase.cpp index bc5244b83..cb43069ba 100644 --- a/src/playlistparsers/parserbase.cpp +++ b/src/playlistparsers/parserbase.cpp @@ -29,7 +29,7 @@ #include "core/shared_ptr.h" #include "core/logging.h" -#include "core/tagreaderclient.h" +#include "tagreader/tagreaderclient.h" #include "collection/collectionbackend.h" #include "settings/playlistsettingspage.h" #include "parserbase.h" @@ -105,9 +105,9 @@ void ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning } } - const TagReaderClient::Result result = TagReaderClient::Instance()->ReadFileBlocking(filename, song); + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(filename, song); if (!result.success()) { - qLog(Error) << "Could not read file" << filename << result.error; + qLog(Error) << "Could not read file" << filename << result.error_string(); } } diff --git a/src/tagreader/albumcovertagdata.cpp b/src/tagreader/albumcovertagdata.cpp new file mode 100644 index 000000000..7e61a001a --- /dev/null +++ b/src/tagreader/albumcovertagdata.cpp @@ -0,0 +1,27 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include + +#include "albumcovertagdata.h" + +AlbumCoverTagData::AlbumCoverTagData(const QByteArray &_data, const QString &_mimetype) + : data(_data), + mimetype(_mimetype) {} diff --git a/src/tagreader/albumcovertagdata.h b/src/tagreader/albumcovertagdata.h new file mode 100644 index 000000000..38311183b --- /dev/null +++ b/src/tagreader/albumcovertagdata.h @@ -0,0 +1,34 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef ALBUMCOVERTAGDATA_H +#define ALBUMCOVERTAGDATA_H + +#include +#include + +class AlbumCoverTagData { + public: + explicit AlbumCoverTagData(const QByteArray &_data = QByteArray(), const QString &_mimetype = QString()); + QByteArray data; + QString mimetype; + QString error; +}; + +#endif // ALBUMCOVERTAGDATA_H diff --git a/src/tagreader/savetagcoverdata.cpp b/src/tagreader/savetagcoverdata.cpp new file mode 100644 index 000000000..4daa2dfdc --- /dev/null +++ b/src/tagreader/savetagcoverdata.cpp @@ -0,0 +1,32 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include + +#include "savetagcoverdata.h" + +SaveTagCoverData::SaveTagCoverData(const QString &_cover_filename, const QByteArray &_cover_data, const QString &_cover_mimetype) + : cover_filename(_cover_filename), + cover_data(_cover_data), + cover_mimetype(_cover_mimetype) {} + +SaveTagCoverData::SaveTagCoverData(const QByteArray &_cover_data, const QString &_cover_mimetype) + : cover_data(_cover_data), + cover_mimetype(_cover_mimetype) {} diff --git a/src/tagreader/savetagcoverdata.h b/src/tagreader/savetagcoverdata.h new file mode 100644 index 000000000..69e964027 --- /dev/null +++ b/src/tagreader/savetagcoverdata.h @@ -0,0 +1,35 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef SAVETAGCOVERDATA_H +#define SAVETAGCOVERDATA_H + +#include +#include + +class SaveTagCoverData { + public: + SaveTagCoverData(const QString &_cover_filename = QString(), const QByteArray &_cover_data = QByteArray(), const QString &_cover_mimetype = QString()); + SaveTagCoverData(const QByteArray &_cover_data, const QString &_cover_mimetype = QString()); + QString cover_filename; + QByteArray cover_data; + QString cover_mimetype; +}; + +#endif // SAVETAGCOVERDATA_H diff --git a/src/tagreader/savetagsoptions.h b/src/tagreader/savetagsoptions.h new file mode 100644 index 000000000..581ebbb67 --- /dev/null +++ b/src/tagreader/savetagsoptions.h @@ -0,0 +1,34 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef SAVETAGSOPTIONS_H +#define SAVETAGSOPTIONS_H + +#include + +enum class SaveTagsOption { + NoType = 0, + Tags = 1, + Playcount = 2, + Rating = 4, + Cover = 8 +}; +Q_DECLARE_FLAGS(SaveTagsOptions, SaveTagsOption) + +#endif // SAVETAGSOPTIONS_H diff --git a/src/tagreader/tagreaderbase.cpp b/src/tagreader/tagreaderbase.cpp new file mode 100644 index 000000000..c14b00a64 --- /dev/null +++ b/src/tagreader/tagreaderbase.cpp @@ -0,0 +1,110 @@ +/* + * Strawberry Music Player + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/logging.h" +#include "tagreaderbase.h" + +using namespace Qt::StringLiterals; + +TagReaderBase::TagReaderBase() = default; +TagReaderBase::~TagReaderBase() = default; + +float TagReaderBase::ConvertPOPMRating(const int POPM_rating) { + + if (POPM_rating < 0x01) return 0.0F; + if (POPM_rating < 0x40) return 0.20F; + if (POPM_rating < 0x80) return 0.40F; + if (POPM_rating < 0xC0) return 0.60F; + if (POPM_rating < 0xFC) return 0.80F; + + return 1.0F; + +} + +int TagReaderBase::ConvertToPOPMRating(const float rating) { + + if (rating < 0.20) return 0x00; + if (rating < 0.40) return 0x01; + if (rating < 0.60) return 0x40; + if (rating < 0.80) return 0x80; + if (rating < 1.0) return 0xC0; + + return 0xFF; + +} + +AlbumCoverTagData TagReaderBase::LoadAlbumCoverTagData(const QString &song_filename, const SaveTagCoverData &save_tag_cover_data) { + + const QString &cover_filename = save_tag_cover_data.cover_filename; + QByteArray cover_data = save_tag_cover_data.cover_data; + QString cover_mimetype = save_tag_cover_data.cover_mimetype; + + if (cover_data.isEmpty() && !cover_filename.isEmpty()) { + qLog(Debug) << "Loading cover from" << cover_filename << "for" << song_filename; + QFile file(cover_filename); + if (!file.open(QIODevice::ReadOnly)) { + qLog(Error) << "Failed to open file" << cover_filename << "for reading:" << file.errorString(); + return AlbumCoverTagData(); + } + cover_data = file.readAll(); + file.close(); + } + + if (!cover_data.isEmpty()) { + if (cover_mimetype.isEmpty()) { + cover_mimetype = QMimeDatabase().mimeTypeForData(cover_data).name(); + } + if (cover_mimetype == "image/jpeg"_L1) { + qLog(Debug) << "Using cover from JPEG data for" << song_filename; + return AlbumCoverTagData(cover_data, cover_mimetype); + } + if (cover_mimetype == "image/png"_L1) { + qLog(Debug) << "Using cover from PNG data for" << song_filename; + return AlbumCoverTagData(cover_data, cover_mimetype); + } + // Convert image to JPEG. + qLog(Debug) << "Converting cover to JPEG data for" << song_filename; + QImage cover_image; + if (!cover_image.loadFromData(cover_data)) { + qLog(Error) << "Failed to load image from cover data for" << song_filename; + return AlbumCoverTagData(); + } + cover_data.clear(); + QBuffer buffer(&cover_data); + if (buffer.open(QIODevice::WriteOnly)) { + cover_image.save(&buffer, "JPEG"); + buffer.close(); + } + return AlbumCoverTagData(cover_data, u"image/jpeg"_s); + } + + return AlbumCoverTagData(); + +} diff --git a/src/tagreader/tagreaderbase.h b/src/tagreader/tagreaderbase.h new file mode 100644 index 000000000..a88ae0199 --- /dev/null +++ b/src/tagreader/tagreaderbase.h @@ -0,0 +1,61 @@ +/* + * Strawberry Music Player + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERBASE_H +#define TAGREADERBASE_H + +#include "config.h" + +#include +#include +#include + +#include "core/song.h" + +#include "tagreaderresult.h" +#include "savetagsoptions.h" +#include "savetagcoverdata.h" +#include "albumcovertagdata.h" + +class TagReaderBase { + public: + explicit TagReaderBase(); + virtual ~TagReaderBase(); + + virtual TagReaderResult IsMediaFile(const QString &filename) const = 0; + + virtual TagReaderResult ReadFile(const QString &filename, Song *song) const = 0; + virtual TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const = 0; + + virtual TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const = 0; + virtual TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const = 0; + + virtual TagReaderResult SaveSongPlaycount(const QString &filename, const uint playcount) const = 0; + virtual TagReaderResult SaveSongRating(const QString &filename, const float rating) const = 0; + + protected: + static float ConvertPOPMRating(const int POPM_rating); + static int ConvertToPOPMRating(const float rating); + + static AlbumCoverTagData LoadAlbumCoverTagData(const QString &song_filename, const SaveTagCoverData &save_tag_cover_data); + + Q_DISABLE_COPY(TagReaderBase) +}; + +#endif // TAGREADERBASE_H diff --git a/src/tagreader/tagreaderclient.cpp b/src/tagreader/tagreaderclient.cpp new file mode 100644 index 000000000..1aa17b812 --- /dev/null +++ b/src/tagreader/tagreaderclient.cpp @@ -0,0 +1,423 @@ +/* + * Strawberry Music Player + * Copyright 2019-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/logging.h" +#include "core/song.h" + +#include "tagreaderclient.h" +#include "tagreadertaglib.h" +#include "tagreaderresult.h" +#include "tagreaderrequest.h" +#include "tagreaderismediafilerequest.h" +#include "tagreaderreadfilerequest.h" +#include "tagreaderwritefilerequest.h" +#include "tagreaderloadcoverdatarequest.h" +#include "tagreaderloadcoverimagerequest.h" +#include "tagreadersavecoverrequest.h" +#include "tagreadersaveplaycountrequest.h" +#include "tagreadersaveratingrequest.h" +#include "tagreaderreply.h" +#include "tagreaderreadfilereply.h" +#include "tagreaderloadcoverdatareply.h" +#include "tagreaderloadcoverimagereply.h" + +using std::dynamic_pointer_cast; +using namespace Qt::StringLiterals; + +TagReaderClient *TagReaderClient::sInstance = nullptr; + +TagReaderClient::TagReaderClient(QObject *parent) + : QObject(parent), + original_thread_(thread()), + abort_(false), + processing_(false) { + + setObjectName(QLatin1String(metaObject()->className())); + + sInstance = this; + +} + +void TagReaderClient::ExitAsync() { + + Q_ASSERT(QThread::currentThread() != thread()); + + abort_ = true; + QMetaObject::invokeMethod(this, &TagReaderClient::Exit, Qt::QueuedConnection); + +} + +void TagReaderClient::Exit() { + + Q_ASSERT(QThread::currentThread() == thread()); + + moveToThread(original_thread_); + Q_EMIT ExitFinished(); + +} + +bool TagReaderClient::HaveRequests() const { + + Q_ASSERT(QThread::currentThread() == thread()); + + { + QMutexLocker l(&mutex_requests_); + return !requests_.isEmpty(); + } + +} + +void TagReaderClient::EnqueueRequest(TagReaderRequestPtr request) { + + Q_ASSERT(QThread::currentThread() != thread()); + + { + QMutexLocker l(&mutex_requests_); + requests_.enqueue(request); + } + + if (!processing_.value()) { + ProcessRequestsAsync(); + } + +} + +TagReaderRequestPtr TagReaderClient::DequeueRequest() { + + Q_ASSERT(QThread::currentThread() == thread()); + + { + QMutexLocker l(&mutex_requests_); + if (requests_.isEmpty()) return TagReaderRequestPtr(); + return requests_.dequeue(); + } + +} + +void TagReaderClient::ProcessRequestsAsync() { + + Q_ASSERT(QThread::currentThread() != thread()); + + QMetaObject::invokeMethod(this, &TagReaderClient::ProcessRequests, Qt::QueuedConnection); + +} + +void TagReaderClient::ProcessRequests() { + + Q_ASSERT(QThread::currentThread() == thread()); + + processing_ = true; + + const QScopeGuard scopeguard_processing = qScopeGuard([this]() { + processing_ = false; + }); + + while (HaveRequests()) { + if (abort_.value()) return; + ProcessRequest(DequeueRequest()); + } + +} + +void TagReaderClient::ProcessRequest(TagReaderRequestPtr request) { + + Q_ASSERT(QThread::currentThread() == thread()); + + TagReaderReplyPtr reply = request->reply; + + TagReaderResult result; + + if (TagReaderIsMediaFileRequestPtr is_media_file_request = std::dynamic_pointer_cast(request)) { + result = tagreader_.IsMediaFile(is_media_file_request->filename); + if (result.error_code == TagReaderResult::ErrorCode::Unsupported) { + result = gmereader_.IsMediaFile(is_media_file_request->filename); + } + } + else if (TagReaderReadFileRequestPtr read_file_request = std::dynamic_pointer_cast(request)) { + Song song; + result = ReadFileBlocking(read_file_request->filename, &song); + if (result.error_code == TagReaderResult::ErrorCode::Unsupported) { + result = gmereader_.ReadFile(read_file_request->filename, &song); + } + if (result.success()) { + if (TagReaderReadFileReplyPtr read_file_reply = std::dynamic_pointer_cast(reply)) { + read_file_reply->set_song(song); + } + } + } + else if (TagReaderWriteFileRequestPtr write_file_request = dynamic_pointer_cast(request)) { + result = WriteFileBlocking(write_file_request->filename, write_file_request->song, write_file_request->save_tags_options, write_file_request->save_tag_cover_data); + } + else if (TagReaderLoadCoverDataRequestPtr load_cover_data_request = dynamic_pointer_cast(request)) { + QByteArray cover_data; + result = LoadCoverDataBlocking(load_cover_data_request->filename, cover_data); + if (result.success()) { + if (TagReaderLoadCoverDataReplyPtr load_cover_data_reply = std::dynamic_pointer_cast(reply)) { + load_cover_data_reply->set_data(cover_data); + } + } + } + else if (TagReaderLoadCoverImageRequestPtr load_cover_image_request = dynamic_pointer_cast(request)) { + QImage cover_image; + result = LoadCoverImageBlocking(load_cover_image_request->filename, cover_image); + if (result.success()) { + if (TagReaderLoadCoverImageReplyPtr load_cover_image_reply = std::dynamic_pointer_cast(reply)) { + load_cover_image_reply->set_image(cover_image); + } + } + } + else if (TagReaderSaveCoverRequestPtr save_cover_request = dynamic_pointer_cast(request)) { + result = SaveCoverBlocking(save_cover_request->filename, save_cover_request->save_tag_cover_data); + } + else if (TagReaderSavePlaycountRequestPtr save_playcount_request = dynamic_pointer_cast(request)) { + result = SaveSongPlaycountBlocking(save_playcount_request->filename, save_playcount_request->playcount); + } + else if (TagReaderSaveRatingRequestPtr save_rating_request = dynamic_pointer_cast(request)) { + result = SaveSongRatingBlocking(save_rating_request->filename, save_rating_request->rating); + } + + reply->set_result(result); + + reply->Finish(); + +} + +bool TagReaderClient::IsMediaFileBlocking(const QString &filename) const { + + Q_ASSERT(QThread::currentThread() != thread()); + + return tagreader_.IsMediaFile(filename).success(); + +} + +TagReaderReplyPtr TagReaderClient::IsMediaFileAsync(const QString &filename) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderIsMediaFileRequestPtr request = TagReaderIsMediaFileRequest::Create(filename); + request->reply = reply; + request->filename = filename; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderResult TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) { + + return tagreader_.ReadFile(filename, song); + +} + +TagReaderReadFileReplyPtr TagReaderClient::ReadFileAsync(const QString &filename) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReadFileReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderReadFileRequestPtr request = TagReaderReadFileRequest::Create(filename); + request->reply = reply; + request->filename = filename; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderResult TagReaderClient::WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) { + + return tagreader_.WriteFile(filename, song, save_tags_options, save_tag_cover_data); + +} + +TagReaderReplyPtr TagReaderClient::WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderWriteFileRequestPtr request = TagReaderWriteFileRequest::Create(filename); + request->reply = reply; + request->filename = filename; + request->song = song; + request->save_tags_options = save_tags_options; + request->save_tag_cover_data = save_tag_cover_data; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderResult TagReaderClient::LoadCoverDataBlocking(const QString &filename, QByteArray &data) { + + return tagreader_.LoadEmbeddedCover(filename, data); + +} + +TagReaderResult TagReaderClient::LoadCoverImageBlocking(const QString &filename, QImage &image) { + + QByteArray data; + TagReaderResult result = LoadCoverDataBlocking(filename, data); + if (result.error_code == TagReaderResult::ErrorCode::Success && !image.loadFromData(data)) { + result.error_code = TagReaderResult::ErrorCode::Unsupported; + result.error_text = QObject::tr("Failed to load image from data for %1").arg(filename); + } + + return result; + +} + +TagReaderLoadCoverDataReplyPtr TagReaderClient::LoadCoverDataAsync(const QString &filename) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderLoadCoverDataReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderLoadCoverDataRequestPtr request = TagReaderLoadCoverDataRequest::Create(filename); + request->reply = reply; + request->filename = filename; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderLoadCoverImageReplyPtr TagReaderClient::LoadCoverImageAsync(const QString &filename) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderLoadCoverImageReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderLoadCoverImageRequestPtr request = TagReaderLoadCoverImageRequest::Create(filename); + request->reply = reply; + request->filename = filename; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderResult TagReaderClient::SaveCoverBlocking(const QString &filename, const SaveTagCoverData &save_tag_cover_data) { + + return tagreader_.SaveEmbeddedCover(filename, save_tag_cover_data); + +} + +TagReaderReplyPtr TagReaderClient::SaveCoverAsync(const QString &filename, const SaveTagCoverData &save_tag_cover_data) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderSaveCoverRequestPtr request = TagReaderSaveCoverRequest::Create(filename); + request->reply = reply; + request->filename = filename; + request->save_tag_cover_data = save_tag_cover_data; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderReplyPtr TagReaderClient::SaveSongPlaycountAsync(const QString &filename, const uint playcount) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderSavePlaycountRequestPtr request = TagReaderSavePlaycountRequest::Create(filename); + request->reply = reply; + request->filename = filename; + request->playcount = playcount; + + EnqueueRequest(request); + + return reply; + +} + +TagReaderResult TagReaderClient::SaveSongPlaycountBlocking(const QString &filename, const uint playcount) { + + return tagreader_.SaveSongPlaycount(filename, playcount); + +} + +void TagReaderClient::SaveSongsPlaycountAsync(const SongList &songs) { + + Q_ASSERT(QThread::currentThread() != thread()); + + for (const Song &song : songs) { + TagReaderReplyPtr reply = SaveSongPlaycountAsync(song.url().toLocalFile(), song.playcount()); + QObject::connect(&*reply, &TagReaderReply::Finished, &*reply, &TagReaderReply::deleteLater); + } + +} + +TagReaderResult TagReaderClient::SaveSongRatingBlocking(const QString &filename, const float rating) { + + return tagreader_.SaveSongRating(filename, rating); + +} + +TagReaderReplyPtr TagReaderClient::SaveSongRatingAsync(const QString &filename, const float rating) { + + Q_ASSERT(QThread::currentThread() != thread()); + + TagReaderReplyPtr reply = TagReaderReply::Create(filename); + + TagReaderSaveRatingRequestPtr request = TagReaderSaveRatingRequest::Create(filename); + request->reply = reply; + request->filename = filename; + request->rating = rating; + + EnqueueRequest(request); + + return reply; + +} + +void TagReaderClient::SaveSongsRatingAsync(const SongList &songs) { + + Q_ASSERT(QThread::currentThread() != thread()); + + for (const Song &song : songs) { + TagReaderReplyPtr reply = SaveSongRatingAsync(song.url().toLocalFile(), song.rating()); + QObject::connect(&*reply, &TagReaderReply::Finished, &*reply, &TagReaderReply::deleteLater); + } + +} diff --git a/src/tagreader/tagreaderclient.h b/src/tagreader/tagreaderclient.h new file mode 100644 index 000000000..998b6e7fc --- /dev/null +++ b/src/tagreader/tagreaderclient.h @@ -0,0 +1,117 @@ +/* + * Strawberry Music Player + * Copyright 2019-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERCLIENT_H +#define TAGREADERCLIENT_H + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "core/shared_ptr.h" +#include "core/mutex_protected.h" +#include "core/song.h" + +#include "tagreadertaglib.h" +#include "tagreadergme.h" +#include "tagreaderrequest.h" +#include "tagreaderresult.h" +#include "tagreaderreply.h" +#include "tagreaderreadfilereply.h" +#include "tagreaderloadcoverdatareply.h" +#include "tagreaderloadcoverimagereply.h" +#include "savetagsoptions.h" +#include "savetagcoverdata.h" + +class QThread; +class Song; + +class TagReaderClient : public QObject { + Q_OBJECT + + public: + explicit TagReaderClient(QObject *parent = nullptr); + + static TagReaderClient *Instance() { return sInstance; } + + void Start(); + void ExitAsync(); + + using SaveOption = SaveTagsOption; + using SaveOptions = SaveTagsOptions; + + bool IsMediaFileBlocking(const QString &filename) const; + TagReaderReplyPtr IsMediaFileAsync(const QString &filename); + + TagReaderResult ReadFileBlocking(const QString &filename, Song *song); + TagReaderReadFileReplyPtr ReadFileAsync(const QString &filename); + + TagReaderResult WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData()); + TagReaderReplyPtr WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options = SaveTagsOption::Tags, const SaveTagCoverData &save_tag_cover_data = SaveTagCoverData()); + + TagReaderResult LoadCoverDataBlocking(const QString &filename, QByteArray &data); + TagReaderResult LoadCoverImageBlocking(const QString &filename, QImage &image); + TagReaderLoadCoverDataReplyPtr LoadCoverDataAsync(const QString &filename); + TagReaderLoadCoverImageReplyPtr LoadCoverImageAsync(const QString &filename); + + TagReaderResult SaveCoverBlocking(const QString &filename, const SaveTagCoverData &save_tag_cover_data); + TagReaderReplyPtr SaveCoverAsync(const QString &filename, const SaveTagCoverData &save_tag_cover_data); + + TagReaderReplyPtr SaveSongPlaycountAsync(const QString &filename, const uint playcount); + TagReaderResult SaveSongPlaycountBlocking(const QString &filename, const uint playcount); + + TagReaderReplyPtr SaveSongRatingAsync(const QString &filename, const float rating); + TagReaderResult SaveSongRatingBlocking(const QString &filename, const float rating); + + private: + bool HaveRequests() const; + void EnqueueRequest(TagReaderRequestPtr request); + TagReaderRequestPtr DequeueRequest(); + void ProcessRequestsAsync(); + void ProcessRequest(TagReaderRequestPtr request); + + Q_SIGNALS: + void ExitFinished(); + + private Q_SLOTS: + void Exit(); + void ProcessRequests(); + + public Q_SLOTS: + void SaveSongsPlaycountAsync(const SongList &songs); + void SaveSongsRatingAsync(const SongList &songs); + + private: + static TagReaderClient *sInstance; + + QThread *original_thread_; + QQueue requests_; + mutable QMutex mutex_requests_; + TagReaderTagLib tagreader_; + TagReaderGME gmereader_; + mutex_protected abort_; + mutex_protected processing_; +}; + +#endif // TAGREADERCLIENT_H diff --git a/ext/libstrawberry-tagreader/tagreadergme.cpp b/src/tagreader/tagreadergme.cpp similarity index 74% rename from ext/libstrawberry-tagreader/tagreadergme.cpp rename to src/tagreader/tagreadergme.cpp index 9a972481e..3a8cd8dbe 100644 --- a/ext/libstrawberry-tagreader/tagreadergme.cpp +++ b/src/tagreader/tagreadergme.cpp @@ -30,7 +30,6 @@ #include "utilities/timeconstants.h" #include "core/logging.h" -#include "core/messagehandler.h" #include "tagreaderbase.h" #include "tagreadertaglib.h" @@ -43,7 +42,7 @@ bool GME::IsSupportedFormat(const QFileInfo &fileinfo) { return fileinfo.exists() && (fileinfo.completeSuffix().endsWith("spc"_L1, Qt::CaseInsensitive) || fileinfo.completeSuffix().endsWith("vgm"_L1), Qt::CaseInsensitive); } -TagReaderBase::Result GME::ReadFile(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song) { +TagReaderResult GME::ReadFile(const QFileInfo &fileinfo, Song *song) { if (fileinfo.completeSuffix().endsWith("spc"_L1), Qt::CaseInsensitive) { return SPC::Read(fileinfo, song); @@ -52,7 +51,7 @@ TagReaderBase::Result GME::ReadFile(const QFileInfo &fileinfo, spb::tagreader::S return VGM::Read(fileinfo, song); } - return TagReaderBase::Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } @@ -69,18 +68,18 @@ quint32 GME::UnpackBytes32(const char *const bytes, size_t length) { } -TagReaderBase::Result GME::SPC::Read(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song) { +TagReaderResult GME::SPC::Read(const QFileInfo &fileinfo, Song *song) { QFile file(fileinfo.filePath()); if (!file.open(QIODevice::ReadOnly)) { - return TagReaderBase::Result(TagReaderBase::Result::ErrorCode::FileOpenError, file.errorString()); + return TagReaderResult(TagReaderResult::ErrorCode::FileOpenError, file.errorString()); } qLog(Debug) << "Reading tags from SPC file" << fileinfo.fileName(); // Check for header -- more reliable than file name alone. - if (!file.read(33).startsWith(QStringLiteral("SNES-SPC700").toLatin1())) { - return TagReaderBase::Result::ErrorCode::Unsupported; + if (!file.read(33).startsWith("SNES-SPC700")) { + return TagReaderResult::ErrorCode::Unsupported; } // First order of business -- get any tag values that exist within the core file information. @@ -113,7 +112,7 @@ TagReaderBase::Result GME::SPC::Read(const QFileInfo &fileinfo, spb::tagreader:: } if (length_in_sec < 0x1FFF) { - song->set_length_nanosec(length_in_sec * kNsecPerSec); + song->set_length_nanosec(static_cast(length_in_sec * kNsecPerSec)); } } @@ -131,7 +130,7 @@ TagReaderBase::Result GME::SPC::Read(const QFileInfo &fileinfo, spb::tagreader:: // Check for XID6 data -- this is infrequently used, but being able to fill in data from this is ideal before trying to rely on APETAG values. // XID6 format follows EA's binary file format standard named "IFF" file.seek(XID6_OFFSET); - if (has_id6 && file.read(4) == QStringLiteral("xid6").toLatin1()) { + if (has_id6 && file.read(4) == "xid6") { QByteArray xid6_head_data = file.read(4); if (xid6_head_data.size() >= 4) { qint64 xid6_size = xid6_head_data[0] | (xid6_head_data[1] << 8) | (xid6_head_data[2] << 16) | xid6_head_data[3]; @@ -162,21 +161,21 @@ TagReaderBase::Result GME::SPC::Read(const QFileInfo &fileinfo, spb::tagreader:: if (ape.hasAPETag()) { TagLib::Tag *tag = ape.tag(); if (!tag) { - return TagReaderBase::Result::ErrorCode::FileParseError; + return TagReaderResult::ErrorCode::FileParseError; } - TagReaderTagLib::AssignTagLibStringToStdString(tag->artist(), song->mutable_artist()); - TagReaderTagLib::AssignTagLibStringToStdString(tag->album(), song->mutable_album()); - TagReaderTagLib::AssignTagLibStringToStdString(tag->title(), song->mutable_title()); - TagReaderTagLib::AssignTagLibStringToStdString(tag->genre(), song->mutable_genre()); + song->set_artist(tag->artist()); + song->set_album(tag->album()); + song->set_title(tag->title()); + song->set_genre(tag->genre()); song->set_track(static_cast(tag->track())); song->set_year(static_cast(tag->year())); } song->set_valid(true); - song->set_filetype(spb::tagreader::SongMetadata_FileType_SPC); + song->set_filetype(Song::FileType::SPC); - return TagReaderBase::Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } @@ -198,23 +197,23 @@ quint64 GME::SPC::ConvertSPCStringToNum(const QByteArray &arr) { } -TagReaderBase::Result GME::VGM::Read(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song) { +TagReaderResult GME::VGM::Read(const QFileInfo &fileinfo, Song *song) { QFile file(fileinfo.filePath()); if (!file.open(QIODevice::ReadOnly)) { - return TagReaderBase::Result(TagReaderBase::Result::ErrorCode::FileOpenError, file.errorString()); + return TagReaderResult(TagReaderResult::ErrorCode::FileOpenError, file.errorString()); } qLog(Debug) << "Reading tags from VGM file" << fileinfo.filePath(); - if (!file.read(4).startsWith(QStringLiteral("Vgm ").toLatin1())) { - return TagReaderBase::Result::ErrorCode::Unsupported; + if (!file.read(4).startsWith("Vgm ")) { + return TagReaderResult::ErrorCode::Unsupported; } file.seek(GD3_TAG_PTR); QByteArray gd3_head = file.read(4); if (gd3_head.size() < 4) { - return TagReaderBase::Result::ErrorCode::FileParseError; + return TagReaderResult::ErrorCode::FileParseError; } quint64 pt = GME::UnpackBytes32(gd3_head.constData(), gd3_head.size()); @@ -226,7 +225,7 @@ TagReaderBase::Result GME::VGM::Read(const QFileInfo &fileinfo, spb::tagreader:: quint64 length = 0; if (!GetPlaybackLength(sample_count_bytes, loop_count_bytes, length)) { - return TagReaderBase::Result::ErrorCode::FileParseError; + return TagReaderResult::ErrorCode::FileParseError; } file.seek(static_cast(GD3_TAG_PTR + pt)); @@ -243,7 +242,7 @@ TagReaderBase::Result GME::VGM::Read(const QFileInfo &fileinfo, spb::tagreader:: fileTagStream.setEncoding(QStringConverter::Utf16); QStringList strings = fileTagStream.readLine(0).split(u'\0'); if (strings.count() < 10) { - return TagReaderBase::Result::ErrorCode::FileParseError; + return TagReaderResult::ErrorCode::FileParseError; } // VGM standard dictates string tag data exist in specific order. @@ -253,11 +252,11 @@ TagReaderBase::Result GME::VGM::Read(const QFileInfo &fileinfo, spb::tagreader:: song->set_album(strings[2].toStdString()); song->set_artist(strings[6].toStdString()); song->set_year(strings[8].left(4).toInt()); - song->set_length_nanosec(length * kNsecPerMsec); + song->set_length_nanosec(static_cast(length * kNsecPerMsec)); song->set_valid(true); - song->set_filetype(spb::tagreader::SongMetadata_FileType_VGM); + song->set_filetype(Song::FileType::VGM); - return TagReaderBase::Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } @@ -288,61 +287,63 @@ bool GME::VGM::GetPlaybackLength(const QByteArray &sample_count_bytes, const QBy TagReaderGME::TagReaderGME() = default; -bool TagReaderGME::IsMediaFile(const QString &filename) const { +TagReaderResult TagReaderGME::IsMediaFile(const QString &filename) const { QFileInfo fileinfo(filename); - return GME::IsSupportedFormat(fileinfo); + return GME::IsSupportedFormat(fileinfo) ? TagReaderResult::ErrorCode::Success : TagReaderResult::ErrorCode::Unsupported; } -TagReaderBase::Result TagReaderGME::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const { +TagReaderResult TagReaderGME::ReadFile(const QString &filename, Song *song) const { QFileInfo fileinfo(filename); return GME::ReadFile(fileinfo, song); } -TagReaderBase::Result TagReaderGME::WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const { +TagReaderResult TagReaderGME::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const { Q_UNUSED(filename); - Q_UNUSED(request); + Q_UNUSED(song); + Q_UNUSED(save_tags_options); + Q_UNUSED(save_tag_cover_data); - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } -TagReaderBase::Result TagReaderGME::LoadEmbeddedArt(const QString &filename, QByteArray &data) const { +TagReaderResult TagReaderGME::LoadEmbeddedCover(const QString &filename, QByteArray &data) const { Q_UNUSED(filename); Q_UNUSED(data); - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } -TagReaderBase::Result TagReaderGME::SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const { +TagReaderResult TagReaderGME::SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const { Q_UNUSED(filename); - Q_UNUSED(request); + Q_UNUSED(save_tag_cover_data); - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } -TagReaderBase::Result TagReaderGME::SaveSongPlaycountToFile(const QString &filename, const uint playcount) const { +TagReaderResult TagReaderGME::SaveSongPlaycount(const QString &filename, const uint playcount) const { Q_UNUSED(filename); Q_UNUSED(playcount); - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } -TagReaderBase::Result TagReaderGME::SaveSongRatingToFile(const QString &filename, const float rating) const { +TagReaderResult TagReaderGME::SaveSongRating(const QString &filename, const float rating) const { Q_UNUSED(filename); Q_UNUSED(rating); - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } diff --git a/ext/libstrawberry-tagreader/tagreadergme.h b/src/tagreader/tagreadergme.h similarity index 75% rename from ext/libstrawberry-tagreader/tagreadergme.h rename to src/tagreader/tagreadergme.h index 4ad5f637b..48cdc79ad 100644 --- a/ext/libstrawberry-tagreader/tagreadergme.h +++ b/src/tagreader/tagreadergme.h @@ -25,11 +25,10 @@ #include #include "tagreaderbase.h" -#include "tagreadermessages.pb.h" namespace GME { bool IsSupportedFormat(const QFileInfo &fileinfo); -TagReaderBase::Result ReadFile(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song); +TagReaderResult ReadFile(const QFileInfo &fileinfo, Song *song); uint32_t UnpackBytes32(const char *const bytes, size_t length); @@ -69,7 +68,7 @@ enum class xID6_TYPE { Integer = 0x4 }; -TagReaderBase::Result Read(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song); +TagReaderResult Read(const QFileInfo &fileinfo, Song *song); qint16 GetNextMemAddressAlign32bit(qint16 input); quint64 ConvertSPCStringToNum(const QByteArray &arr); } // namespace SPC @@ -85,7 +84,7 @@ constexpr int LOOP_SAMPLE_COUNT = 0x20; constexpr int SAMPLE_TIMEBASE = 44100; constexpr int GST_GME_LOOP_TIME_MS = 8000; -TagReaderBase::Result Read(const QFileInfo &fileinfo, spb::tagreader::SongMetadata *song); +TagReaderResult Read(const QFileInfo &fileinfo, Song *song); // Takes in two QByteArrays, expected to be 4 bytes long. Desired length is returned via output parameter out_length. Returns false on error. bool GetPlaybackLength(const QByteArray &sample_count_bytes, const QByteArray &loop_count_bytes, quint64 &out_length); @@ -100,16 +99,16 @@ class TagReaderGME : public TagReaderBase { public: explicit TagReaderGME(); - bool IsMediaFile(const QString &filename) const override; + TagReaderResult IsMediaFile(const QString &filename) const override; - Result ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const override; - Result WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const override; + TagReaderResult ReadFile(const QString &filename, Song *song) const override; + TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const override; - Result LoadEmbeddedArt(const QString &filename, QByteArray &data) const override; - Result SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const override; + TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const override; + TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const override; - Result SaveSongPlaycountToFile(const QString &filename, const uint playcount) const override; - Result SaveSongRatingToFile(const QString &filename, const float rating) const override; + TagReaderResult SaveSongPlaycount(const QString &filename, const uint playcount) const override; + TagReaderResult SaveSongRating(const QString &filename, const float rating) const override; }; #endif // TAGREADERGME_H diff --git a/src/tagreader/tagreaderismediafilerequest.cpp b/src/tagreader/tagreaderismediafilerequest.cpp new file mode 100644 index 000000000..1383c3e6f --- /dev/null +++ b/src/tagreader/tagreaderismediafilerequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderismediafilerequest.h" + +TagReaderIsMediaFileRequest::TagReaderIsMediaFileRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreaderismediafilerequest.h b/src/tagreader/tagreaderismediafilerequest.h new file mode 100644 index 000000000..0953bf5d8 --- /dev/null +++ b/src/tagreader/tagreaderismediafilerequest.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERISMEDIAFILEREQUEST_H +#define TAGREADERISMEDIAFILEREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderIsMediaFileRequest : public TagReaderRequest { + public: + explicit TagReaderIsMediaFileRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } +}; + +using TagReaderIsMediaFileRequestPtr = std::shared_ptr; + +#endif // TAGREADERISMEDIAFILEREQUEST_H diff --git a/src/tagreader/tagreaderloadcoverdatareply.cpp b/src/tagreader/tagreaderloadcoverdatareply.cpp new file mode 100644 index 000000000..dc3f5c32c --- /dev/null +++ b/src/tagreader/tagreaderloadcoverdatareply.cpp @@ -0,0 +1,40 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "core/logging.h" +#include "tagreaderloadcoverdatareply.h" + +TagReaderLoadCoverDataReply::TagReaderLoadCoverDataReply(const QString &_filename, QObject *parent) + : TagReaderReply(_filename, parent) {} + +void TagReaderLoadCoverDataReply::Finish() { + + qLog(Debug) << "Finishing tagreader reply for" << filename_; + + finished_ = true; + + Q_EMIT TagReaderReply::Finished(filename_, result_); + Q_EMIT TagReaderLoadCoverDataReply::Finished(filename_, data_, result_); + + QObject::disconnect(this, &TagReaderReply::Finished, nullptr, nullptr); + QObject::disconnect(this, &TagReaderLoadCoverDataReply::Finished, nullptr, nullptr); + +} diff --git a/src/tagreader/tagreaderloadcoverdatareply.h b/src/tagreader/tagreaderloadcoverdatareply.h new file mode 100644 index 000000000..906cfe495 --- /dev/null +++ b/src/tagreader/tagreaderloadcoverdatareply.h @@ -0,0 +1,51 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERLOADCOVERDATAREPLY_H +#define TAGREADERLOADCOVERDATAREPLY_H + +#include +#include + +#include "core/shared_ptr.h" +#include "core/song.h" +#include "tagreaderreply.h" +#include "tagreaderresult.h" + +class TagReaderLoadCoverDataReply : public TagReaderReply { + Q_OBJECT + + public: + explicit TagReaderLoadCoverDataReply(const QString &_filename, QObject *parent = nullptr); + + void Finish() override; + + QByteArray data() const { return data_; } + void set_data(const QByteArray &data) { data_ = data; } + + Q_SIGNALS: + void Finished(const QString &filename, const QByteArray &data, const TagReaderResult &result); + + private: + QByteArray data_; +}; + +using TagReaderLoadCoverDataReplyPtr = SharedPtr; + +#endif // TAGREADERLOADCOVERDATAREPLY_H diff --git a/src/tagreader/tagreaderloadcoverdatarequest.cpp b/src/tagreader/tagreaderloadcoverdatarequest.cpp new file mode 100644 index 000000000..5c3444f80 --- /dev/null +++ b/src/tagreader/tagreaderloadcoverdatarequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderloadcoverdatarequest.h" + +TagReaderLoadCoverDataRequest::TagReaderLoadCoverDataRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreaderloadcoverdatarequest.h b/src/tagreader/tagreaderloadcoverdatarequest.h new file mode 100644 index 000000000..b7e7b7802 --- /dev/null +++ b/src/tagreader/tagreaderloadcoverdatarequest.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERLOADCOVERDATAREQUEST_H +#define TAGREADERLOADCOVERDATAREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderLoadCoverDataRequest : public TagReaderRequest { + public: + explicit TagReaderLoadCoverDataRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } +}; + +using TagReaderLoadCoverDataRequestPtr = SharedPtr; + +#endif // TAGREADERLOADCOVERDATAREQUEST_H diff --git a/src/tagreader/tagreaderloadcoverimagereply.cpp b/src/tagreader/tagreaderloadcoverimagereply.cpp new file mode 100644 index 000000000..2a2fcfc7e --- /dev/null +++ b/src/tagreader/tagreaderloadcoverimagereply.cpp @@ -0,0 +1,39 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "core/logging.h" +#include "tagreaderloadcoverimagereply.h" + +TagReaderLoadCoverImageReply::TagReaderLoadCoverImageReply(const QString &_filename, QObject *parent) + : TagReaderReply(_filename, parent) {} + +void TagReaderLoadCoverImageReply::Finish() { + + qLog(Debug) << "Finishing tagreader reply for" << filename_; + + finished_ = true; + + Q_EMIT TagReaderReply::Finished(filename_, result_); + Q_EMIT TagReaderLoadCoverImageReply::Finished(filename_, image_, result_); + + QObject::disconnect(this, &TagReaderLoadCoverImageReply::Finished, nullptr, nullptr); + +} diff --git a/src/tagreader/tagreaderloadcoverimagereply.h b/src/tagreader/tagreaderloadcoverimagereply.h new file mode 100644 index 000000000..1301adb10 --- /dev/null +++ b/src/tagreader/tagreaderloadcoverimagereply.h @@ -0,0 +1,51 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERLOADCOVERIMAGEREPLY_H +#define TAGREADERLOADCOVERIMAGEREPLY_H + +#include +#include + +#include "core/shared_ptr.h" +#include "core/song.h" +#include "tagreaderreply.h" +#include "tagreaderresult.h" + +class TagReaderLoadCoverImageReply : public TagReaderReply { + Q_OBJECT + + public: + explicit TagReaderLoadCoverImageReply(const QString &_filename, QObject *parent = nullptr); + + void Finish() override; + + QImage image() const { return image_; } + void set_image(const QImage &image) { image_ = image; } + + Q_SIGNALS: + void Finished(const QString &filename, const QImage &image, const TagReaderResult &result); + + private: + QImage image_; +}; + +using TagReaderLoadCoverImageReplyPtr = SharedPtr; + +#endif // TAGREADERLOADCOVERIMAGEREPLY_H diff --git a/src/tagreader/tagreaderloadcoverimagerequest.cpp b/src/tagreader/tagreaderloadcoverimagerequest.cpp new file mode 100644 index 000000000..aa5fc0709 --- /dev/null +++ b/src/tagreader/tagreaderloadcoverimagerequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderloadcoverimagerequest.h" + +TagReaderLoadCoverImageRequest::TagReaderLoadCoverImageRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreaderloadcoverimagerequest.h b/src/tagreader/tagreaderloadcoverimagerequest.h new file mode 100644 index 000000000..6ae9cfb4a --- /dev/null +++ b/src/tagreader/tagreaderloadcoverimagerequest.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERLOADCOVERIMAGEREQUEST_H +#define TAGREADERLOADCOVERIMAGEREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderLoadCoverImageRequest : public TagReaderRequest { + public: + explicit TagReaderLoadCoverImageRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } +}; + +using TagReaderLoadCoverImageRequestPtr = SharedPtr; + +#endif // TAGREADERLOADEMBEDDEDCOVERASIMAGEREQUEST_H diff --git a/src/tagreader/tagreaderreadfilereply.cpp b/src/tagreader/tagreaderreadfilereply.cpp new file mode 100644 index 000000000..97abd16d5 --- /dev/null +++ b/src/tagreader/tagreaderreadfilereply.cpp @@ -0,0 +1,39 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "core/logging.h" +#include "tagreaderreadfilereply.h" + +TagReaderReadFileReply::TagReaderReadFileReply(const QString &_filename, QObject *parent) + : TagReaderReply(_filename, parent) {} + +void TagReaderReadFileReply::Finish() { + + qLog(Debug) << "Finishing tagreader reply for" << filename_; + + finished_ = true; + + Q_EMIT TagReaderReply::Finished(filename_, result_); + Q_EMIT TagReaderReadFileReply::Finished(filename_, song_, result_); + + QObject::disconnect(this, &TagReaderReadFileReply::Finished, nullptr, nullptr); + +} diff --git a/src/tagreader/tagreaderreadfilereply.h b/src/tagreader/tagreaderreadfilereply.h new file mode 100644 index 000000000..471d801e1 --- /dev/null +++ b/src/tagreader/tagreaderreadfilereply.h @@ -0,0 +1,50 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERREADFILEREPLY_H +#define TAGREADERREADFILEREPLY_H + +#include + +#include "core/shared_ptr.h" +#include "core/song.h" +#include "tagreaderreply.h" +#include "tagreaderresult.h" + +class TagReaderReadFileReply : public TagReaderReply { + Q_OBJECT + + public: + explicit TagReaderReadFileReply(const QString &_filename, QObject *parent = nullptr); + + void Finish() override; + + Song song() const { return song_; } + void set_song(const Song &song) { song_ = song; } + + Q_SIGNALS: + void Finished(const QString &filename, const Song &song, const TagReaderResult &result); + + private: + Song song_; +}; + +using TagReaderReadFileReplyPtr = SharedPtr; + +#endif // TAGREADERREADFILEREPLY_H diff --git a/src/tagreader/tagreaderreadfilerequest.cpp b/src/tagreader/tagreaderreadfilerequest.cpp new file mode 100644 index 000000000..df5cf9507 --- /dev/null +++ b/src/tagreader/tagreaderreadfilerequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderreadfilerequest.h" + +TagReaderReadFileRequest::TagReaderReadFileRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreaderreadfilerequest.h b/src/tagreader/tagreaderreadfilerequest.h new file mode 100644 index 000000000..1dc196be3 --- /dev/null +++ b/src/tagreader/tagreaderreadfilerequest.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERREADFILEREQUEST_H +#define TAGREADERREADFILEREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderReadFileRequest : public TagReaderRequest { + public: + explicit TagReaderReadFileRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } +}; + +using TagReaderReadFileRequestPtr = SharedPtr; + +#endif // TAGREADERREADFILEREQUEST_H diff --git a/src/tagreader/tagreaderreply.cpp b/src/tagreader/tagreaderreply.cpp new file mode 100644 index 000000000..ea2daba39 --- /dev/null +++ b/src/tagreader/tagreaderreply.cpp @@ -0,0 +1,51 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "core/logging.h" + +#include "tagreaderreply.h" + +TagReaderReply::TagReaderReply(const QString &filename, QObject *parent) + : QObject(parent), + filename_(filename), + finished_(false) { + + qLog(Debug) << "New tagreader reply for" << filename_; + +} + +TagReaderReply::~TagReaderReply() { + + qLog(Debug) << "Deleting tagreader reply for" << filename_; + +} + +void TagReaderReply::Finish() { + + qLog(Debug) << "Finishing tagreader reply for" << filename_; + + finished_ = true; + + Q_EMIT Finished(filename_, result_); + + QObject::disconnect(this, &TagReaderReply::Finished, nullptr, nullptr); + +} diff --git a/src/tagreader/tagreaderreply.h b/src/tagreader/tagreaderreply.h new file mode 100644 index 000000000..16fcf88c2 --- /dev/null +++ b/src/tagreader/tagreaderreply.h @@ -0,0 +1,67 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERREPLY_H +#define TAGREADERREPLY_H + +#include +#include + +#include "core/shared_ptr.h" +#include "tagreaderresult.h" + +class TagReaderReply : public QObject { + Q_OBJECT + + public: + explicit TagReaderReply(const QString &filename, QObject *parent = nullptr); + virtual ~TagReaderReply() override; + + template + static SharedPtr Create(const QString &filename) { + + SharedPtr reply; + reply.reset(new T(filename), [](QObject *obj) { obj->deleteLater(); }); + return reply; + + } + + QString filename() const { return filename_; } + + TagReaderResult result() const { return result_; } + void set_result(const TagReaderResult &result) { result_ = result; } + + bool finished() const { return finished_; } + bool success() const { return result_.success(); } + QString error() const { return result_.error_string(); } + + virtual void Finish(); + + Q_SIGNALS: + void Finished(const QString &filename, const TagReaderResult &result); + + protected: + const QString filename_; + bool finished_; + TagReaderResult result_; +}; + +using TagReaderReplyPtr = SharedPtr; + +#endif // TAGREADERREPLY_H diff --git a/src/tagreader/tagreaderrequest.cpp b/src/tagreader/tagreaderrequest.cpp new file mode 100644 index 000000000..531058caf --- /dev/null +++ b/src/tagreader/tagreaderrequest.cpp @@ -0,0 +1,34 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "core/logging.h" + +#include "tagreaderrequest.h" + +TagReaderRequest::TagReaderRequest(const QString &_filename) : filename(_filename) { + + qLog(Debug) << "New tagreader request for" << filename; + +} + +TagReaderRequest::~TagReaderRequest() { + + qLog(Debug) << "Deleting tagreader request for" << filename; + +} diff --git a/src/tagreader/tagreaderrequest.h b/src/tagreader/tagreaderrequest.h new file mode 100644 index 000000000..5845bd5d8 --- /dev/null +++ b/src/tagreader/tagreaderrequest.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERREQUEST_H +#define TAGREADERREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderreply.h" + +class TagReaderRequest { + public: + explicit TagReaderRequest(const QString &_filename); + virtual ~TagReaderRequest(); + QString filename; + TagReaderReplyPtr reply; +}; + +using TagReaderRequestPtr = SharedPtr; + +#endif // TAGREADERREQUEST_H diff --git a/src/tagreader/tagreaderresult.cpp b/src/tagreader/tagreaderresult.cpp new file mode 100644 index 000000000..6b57d4a51 --- /dev/null +++ b/src/tagreader/tagreaderresult.cpp @@ -0,0 +1,47 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderresult.h" + +QString TagReaderResult::error_string() const { + + switch (error_code) { + case ErrorCode::Success: + return QObject::tr("Success"); + case ErrorCode::Unsupported: + return QObject::tr("File is unsupported"); + case ErrorCode::FilenameMissing: + return QObject::tr("Filename is missing"); + case ErrorCode::FileDoesNotExist: + return QObject::tr("File does not exist"); + case ErrorCode::FileOpenError: + return QObject::tr("File could not be opened"); + case ErrorCode::FileParseError: + return QObject::tr("Could not parse file"); + case ErrorCode::FileSaveError: + return QObject::tr("Could save file"); + case ErrorCode::CustomError: + return error_text; + } + + return QObject::tr("Unknown error"); + +} diff --git a/src/tagreader/tagreaderresult.h b/src/tagreader/tagreaderresult.h new file mode 100644 index 000000000..c15c64e23 --- /dev/null +++ b/src/tagreader/tagreaderresult.h @@ -0,0 +1,44 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERRESULT_H +#define TAGREADERRESULT_H + +#include + +class TagReaderResult { + public: + enum class ErrorCode { + Success, + Unsupported, + FilenameMissing, + FileDoesNotExist, + FileOpenError, + FileParseError, + FileSaveError, + CustomError, + }; + TagReaderResult(const ErrorCode _error_code = ErrorCode::Unsupported, const QString &_error_text = QString()) : error_code(_error_code), error_text(_error_text) {} + ErrorCode error_code; + QString error_text; + bool success() const { return error_code == ErrorCode::Success; } + QString error_string() const; +}; + +#endif // TAGREADERRESULT_H diff --git a/src/tagreader/tagreadersavecoverrequest.cpp b/src/tagreader/tagreadersavecoverrequest.cpp new file mode 100644 index 000000000..4d71289ba --- /dev/null +++ b/src/tagreader/tagreadersavecoverrequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreadersavecoverrequest.h" + +TagReaderSaveCoverRequest::TagReaderSaveCoverRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreadersavecoverrequest.h b/src/tagreader/tagreadersavecoverrequest.h new file mode 100644 index 000000000..c2c3aef5f --- /dev/null +++ b/src/tagreader/tagreadersavecoverrequest.h @@ -0,0 +1,43 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERSAVECOVERREQUEST_H +#define TAGREADERSAVECOVERREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" +#include "savetagcoverdata.h" + +using std::make_shared; + +class TagReaderSaveCoverRequest : public TagReaderRequest { + public: + + explicit TagReaderSaveCoverRequest(const QString &_filename); + + static SharedPtr Create(const QString &filename) { return make_shared(filename); } + + SaveTagCoverData save_tag_cover_data; +}; + +using TagReaderSaveCoverRequestPtr = SharedPtr; + +#endif // TAGREADERSAVECOVERREQUEST_H diff --git a/src/tagreader/tagreadersaveplaycountrequest.cpp b/src/tagreader/tagreadersaveplaycountrequest.cpp new file mode 100644 index 000000000..275b5a03a --- /dev/null +++ b/src/tagreader/tagreadersaveplaycountrequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreadersaveplaycountrequest.h" + +TagReaderSavePlaycountRequest::TagReaderSavePlaycountRequest(const QString &_filename) : TagReaderRequest(_filename), playcount(0) {} diff --git a/src/tagreader/tagreadersaveplaycountrequest.h b/src/tagreader/tagreadersaveplaycountrequest.h new file mode 100644 index 000000000..9fb0c33d6 --- /dev/null +++ b/src/tagreader/tagreadersaveplaycountrequest.h @@ -0,0 +1,39 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERSAVEPLAYCOUNTREQUEST_H +#define TAGREADERSAVEPLAYCOUNTREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderSavePlaycountRequest : public TagReaderRequest { + public: + explicit TagReaderSavePlaycountRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } + uint playcount; +}; + +using TagReaderSavePlaycountRequestPtr = SharedPtr; + +#endif // TAGREADERSAVEPLAYCOUNTREQUEST_H diff --git a/src/tagreader/tagreadersaveratingrequest.cpp b/src/tagreader/tagreadersaveratingrequest.cpp new file mode 100644 index 000000000..14d7c5310 --- /dev/null +++ b/src/tagreader/tagreadersaveratingrequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreadersaveratingrequest.h" + +TagReaderSaveRatingRequest::TagReaderSaveRatingRequest(const QString &_filename) : TagReaderRequest(_filename), rating(0.0F) {} diff --git a/src/tagreader/tagreadersaveratingrequest.h b/src/tagreader/tagreadersaveratingrequest.h new file mode 100644 index 000000000..6df8b88d3 --- /dev/null +++ b/src/tagreader/tagreadersaveratingrequest.h @@ -0,0 +1,39 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERSAVERATINGREQUEST_H +#define TAGREADERSAVERATINGREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "tagreaderrequest.h" + +using std::make_shared; + +class TagReaderSaveRatingRequest : public TagReaderRequest { + public: + explicit TagReaderSaveRatingRequest(const QString &_filename); + static SharedPtr Create(const QString &filename) { return make_shared(filename); } + float rating; +}; + +using TagReaderSaveRatingRequestPtr = SharedPtr; + +#endif // TAGREADERSAVERATINGREQUEST_H diff --git a/ext/libstrawberry-tagreader/tagreadertaglib.cpp b/src/tagreader/tagreadertaglib.cpp similarity index 69% rename from ext/libstrawberry-tagreader/tagreadertaglib.cpp rename to src/tagreader/tagreadertaglib.cpp index 122b0854f..c24db8d6c 100644 --- a/ext/libstrawberry-tagreader/tagreadertaglib.cpp +++ b/src/tagreader/tagreadertaglib.cpp @@ -1,26 +1,27 @@ -/* This file is part of Strawberry. - Copyright 2013, David Sansome - Copyright 2018-2024, Jonas Kvinge - - Strawberry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Strawberry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Strawberry. If not, see . -*/ +/* + * Strawberry Music Player + * Copyright 2013, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ #include "config.h" #include "tagreadertaglib.h" -#include #include #include #include @@ -94,9 +95,12 @@ #include #include "core/logging.h" -#include "core/messagehandler.h" +#include "core/song.h" #include "utilities/timeconstants.h" +#include "albumcovertagdata.h" + +using std::unique_ptr; using namespace Qt::StringLiterals; #undef TStringToQString @@ -113,7 +117,6 @@ constexpr char kID3v2_Compilation[] = "TCMP"; constexpr char kID3v2_OriginalReleaseTime[] = "TDOR"; constexpr char kID3v2_OriginalReleaseYear[] = "TORY"; constexpr char kID3v2_UnsychronizedLyrics[] = "USLT"; -constexpr char kID3v2_SynchronizedLyrics[] = "SYLT"; constexpr char kID3v2_CoverArt[] = "APIC"; constexpr char kID3v2_CommercialFrame[] = "COMM"; constexpr char kID3v2_FMPS_Playcount[] = "FMPS_Playcount"; @@ -263,50 +266,53 @@ TagReaderTagLib::~TagReaderTagLib() { delete factory_; } -bool TagReaderTagLib::IsMediaFile(const QString &filename) const { +TagReaderResult TagReaderTagLib::IsMediaFile(const QString &filename) const { qLog(Debug) << "Checking for valid file" << filename; - std::unique_ptr fileref(factory_->GetFileRef(filename)); - return fileref && !fileref->isNull() && fileref->file() && fileref->tag(); + unique_ptr fileref(factory_->GetFileRef(filename)); + return fileref && + !fileref->isNull() && + fileref->file() && + fileref->tag() ? TagReaderResult::ErrorCode::Success : TagReaderResult::ErrorCode::Unsupported; } -spb::tagreader::SongMetadata_FileType TagReaderTagLib::GuessFileType(TagLib::FileRef *fileref) const { +Song::FileType TagReaderTagLib::GuessFileType(TagLib::FileRef *fileref) const { - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_WAV; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_FLAC; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_WAVPACK; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_OGGFLAC; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_OGGVORBIS; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_OGGOPUS; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_OGGSPEEX; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_MPEG; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_MP4; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_ASF; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_AIFF; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_MPC; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_TRUEAUDIO; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_APE; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_MOD; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_S3M; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_XM; - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_IT; + if (dynamic_cast(fileref->file())) return Song::FileType::WAV; + if (dynamic_cast(fileref->file())) return Song::FileType::FLAC; + if (dynamic_cast(fileref->file())) return Song::FileType::WavPack; + if (dynamic_cast(fileref->file())) return Song::FileType::OggFlac; + if (dynamic_cast(fileref->file())) return Song::FileType::OggVorbis; + if (dynamic_cast(fileref->file())) return Song::FileType::OggOpus; + if (dynamic_cast(fileref->file())) return Song::FileType::OggSpeex; + if (dynamic_cast(fileref->file())) return Song::FileType::MPEG; + if (dynamic_cast(fileref->file())) return Song::FileType::MP4; + if (dynamic_cast(fileref->file())) return Song::FileType::ASF; + if (dynamic_cast(fileref->file())) return Song::FileType::AIFF; + if (dynamic_cast(fileref->file())) return Song::FileType::MPC; + if (dynamic_cast(fileref->file())) return Song::FileType::TrueAudio; + if (dynamic_cast(fileref->file())) return Song::FileType::APE; + if (dynamic_cast(fileref->file())) return Song::FileType::MOD; + if (dynamic_cast(fileref->file())) return Song::FileType::S3M; + if (dynamic_cast(fileref->file())) return Song::FileType::XM; + if (dynamic_cast(fileref->file())) return Song::FileType::IT; #ifdef HAVE_TAGLIB_DSFFILE - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_DSF; + if (dynamic_cast(fileref->file())) return Song::FileType::DSF; #endif #ifdef HAVE_TAGLIB_DSDIFFFILE - if (dynamic_cast(fileref->file())) return spb::tagreader::SongMetadata_FileType_DSDIFF; + if (dynamic_cast(fileref->file())) return Song::FileType::DSDIFF; #endif - return spb::tagreader::SongMetadata_FileType_UNKNOWN; + return Song::FileType::Unknown; } -TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::tagreader::SongMetadata *song) const { +TagReaderResult TagReaderTagLib::ReadFile(const QString &filename, Song *song) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } qLog(Debug) << "Reading tags from" << filename; @@ -314,13 +320,12 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta const QFileInfo fileinfo(filename); if (!fileinfo.exists()) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } - const QByteArray url = QUrl::fromLocalFile(filename).toEncoded(); - const QByteArray basefilename = fileinfo.fileName().toUtf8(); - song->set_basefilename(basefilename.constData(), basefilename.length()); - song->set_url(url.constData(), url.size()); + const QUrl url = QUrl::fromLocalFile(filename); + song->set_basefilename(fileinfo.fileName()); + song->set_url(url); song->set_filesize(fileinfo.size()); song->set_mtime(fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL); song->set_ctime(fileinfo.birthTime().isValid() ? std::max(fileinfo.birthTime().toSecsSinceEpoch(), 0LL) : fileinfo.lastModified().isValid() ? std::max(fileinfo.lastModified().toSecsSinceEpoch(), 0LL) : 0LL); @@ -329,10 +334,10 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta } song->set_lastseen(QDateTime::currentSecsSinceEpoch()); - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } song->set_filetype(GuessFileType(fileref.get())); @@ -345,10 +350,10 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta TagLib::Tag *tag = fileref->tag(); if (tag) { - AssignTagLibStringToStdString(tag->title(), song->mutable_title()); - AssignTagLibStringToStdString(tag->artist(), song->mutable_artist()); // TPE1 - AssignTagLibStringToStdString(tag->album(), song->mutable_album()); - AssignTagLibStringToStdString(tag->genre(), song->mutable_genre()); + song->set_title(tag->title()); + song->set_artist(tag->artist()); // TPE1 + song->set_album(tag->album()); + song->set_genre(tag->genre()); song->set_year(static_cast(tag->year())); song->set_track(static_cast(tag->track())); song->set_valid(true); @@ -387,7 +392,9 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta } } } - if (tag) AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + if (tag) { + song->set_comment(tag->comment()); + } } else if (TagLib::WavPack::File *file_wavpack = dynamic_cast(fileref->file())) { @@ -395,7 +402,9 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta if (file_wavpack->APETag()) { ParseAPETags(file_wavpack->APETag()->itemListMap(), &disc, &compilation, song); } - if (tag) AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + if (tag) { + song->set_comment(tag->comment()); + } } else if (TagLib::APE::File *file_ape = dynamic_cast(fileref->file())) { @@ -403,7 +412,9 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta if (file_ape->APETag()) { ParseAPETags(file_ape->APETag()->itemListMap(), &disc, &compilation, song); } - if (tag) AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + if (tag) { + song->set_comment(tag->comment()); + } } else if (TagLib::MPEG::File *file_mpeg = dynamic_cast(fileref->file())) { @@ -422,7 +433,7 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta else if (TagLib::ASF::File *file_asf = dynamic_cast(fileref->file())) { song->set_bitdepth(file_asf->audioProperties()->bitsPerSample()); if (file_asf->tag()) { - AssignTagLibStringToStdString(file_asf->tag()->comment(), song->mutable_comment()); + song->set_comment(file_asf->tag()->comment()); ParseASFTags(file_asf->tag(), &disc, &compilation, song); } } @@ -431,7 +442,9 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta if (file_mpc->APETag()) { ParseAPETags(file_mpc->APETag()->itemListMap(), &disc, &compilation, song); } - if (tag) AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + if (tag) { + song->set_comment(tag->comment()); + } } else if (TagLib::RIFF::WAV::File *file_wav = dynamic_cast(fileref->file())) { @@ -441,7 +454,7 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta } else if (tag) { - AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + song->set_comment(tag->comment()); } if (!disc.isEmpty()) { @@ -456,9 +469,9 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta } if (compilation.isEmpty()) { - // well, it wasn't set, but if the artist is VA assume it's a compilation - const QString albumartist = QString::fromStdString(song->albumartist()); - const QString artist = QString::fromStdString(song->artist()); + // Compilation wasn't set, but if the artist is VA assume it's a compilation + const QString &albumartist = song->albumartist(); + const QString &artist = song->artist(); if (artist.compare("various artists"_L1) == 0 || albumartist.compare("various artists"_L1) == 0) { song->set_compilation(true); } @@ -467,7 +480,7 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta song->set_compilation(compilation.toInt() == 1); } - if (!lyrics.isEmpty()) song->set_lyrics(lyrics.toStdString()); + if (!lyrics.isEmpty()) song->set_lyrics(lyrics); // Set integer fields to -1 if they're not valid @@ -480,34 +493,34 @@ TagReaderBase::Result TagReaderTagLib::ReadFile(const QString &filename, spb::ta if (song->bitrate() <= 0) { song->set_bitrate(-1); } if (song->lastplayed() <= 0) { song->set_lastplayed(-1); } - if (song->filetype() == spb::tagreader::SongMetadata_FileType_UNKNOWN) { + if (song->filetype() == Song::FileType::Unknown) { qLog(Error) << "Unknown audio filetype reading" << filename; - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } qLog(Debug) << "Got tags for" << filename; - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } -void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const { +void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QString *compilation, Song *song) const { TagLib::ID3v2::FrameListMap map = tag->frameListMap(); if (map.contains(kID3v2_Disc)) *disc = TagLibStringToQString(map[kID3v2_Disc].front()->toString()).trimmed(); - if (map.contains(kID3v2_Composer)) AssignTagLibStringToStdString(map[kID3v2_Composer].front()->toString(), song->mutable_composer()); + if (map.contains(kID3v2_Composer)) song->set_composer(map[kID3v2_Composer].front()->toString()); // content group - if (map.contains(kID3v2_Grouping)) AssignTagLibStringToStdString(map[kID3v2_Grouping].front()->toString(), song->mutable_grouping()); + if (map.contains(kID3v2_Grouping)) song->set_grouping(map[kID3v2_Grouping].front()->toString()); // original artist/performer - if (map.contains(kID3v2_Performer)) AssignTagLibStringToStdString(map[kID3v2_Performer].front()->toString(), song->mutable_performer()); + if (map.contains(kID3v2_Performer)) song->set_performer(map[kID3v2_Performer].front()->toString()); // Skip TPE1 (which is the artist) here because we already fetched it // non-standard: Apple, Microsoft - if (map.contains(kID3v2_AlbumArtist)) AssignTagLibStringToStdString(map[kID3v2_AlbumArtist].front()->toString(), song->mutable_albumartist()); + if (map.contains(kID3v2_AlbumArtist)) song->set_albumartist(map[kID3v2_AlbumArtist].front()->toString()); if (map.contains(kID3v2_Compilation)) *compilation = TagLibStringToQString(map[kID3v2_Compilation].front()->toString()).trimmed(); @@ -519,10 +532,7 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt } if (map.contains(kID3v2_UnsychronizedLyrics)) { - AssignTagLibStringToStdString(map[kID3v2_UnsychronizedLyrics].front()->toString(), song->mutable_lyrics()); - } - else if (map.contains(kID3v2_SynchronizedLyrics)) { - AssignTagLibStringToStdString(map[kID3v2_SynchronizedLyrics].front()->toString(), song->mutable_lyrics()); + song->set_lyrics(map[kID3v2_UnsychronizedLyrics].front()->toString()); } if (map.contains(kID3v2_CoverArt)) song->set_art_embedded(true); @@ -532,7 +542,7 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt const TagLib::ID3v2::CommentsFrame *frame = dynamic_cast(map[kID3v2_CommercialFrame][i]); if (frame && TagLibStringToQString(frame->description()) != "iTunNORM"_L1) { - AssignTagLibStringToStdString(frame->text(), song->mutable_comment()); + song->set_comment(TagLibStringToQString(frame->text())); break; } } @@ -574,7 +584,7 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt if (TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast(map[kID3v2_Unique_File_Identifier][i])) { const TagLib::PropertyMap property_map = frame->asProperties(); if (property_map.contains(kID3v2_MusicBrainz_RecordingId)) { - AssignTagLibStringToStdString(property_map[kID3v2_MusicBrainz_RecordingId].toString(), song->mutable_musicbrainz_recording_id()); + song->set_musicbrainz_recording_id(TagLibStringToQString(property_map[kID3v2_MusicBrainz_RecordingId].toString())); } } } @@ -586,37 +596,37 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt const TagLib::StringList frame_field_list = frame->fieldList(); if (frame_field_list.size() != 2) continue; if (frame->description() == kID3v2_AcoustId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_acoustid_id()); + song->set_acoustid_id(frame_field_list.back()); } if (frame->description() == kID3v2_AcoustId_Fingerprint) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_acoustid_fingerprint()); + song->set_acoustid_fingerprint(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_AlbumArtistId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_album_artist_id()); + song->set_musicbrainz_album_artist_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_ArtistId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_artist_id()); + song->set_musicbrainz_artist_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_OriginalArtistId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_original_artist_id()); + song->set_musicbrainz_original_artist_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_AlbumId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_album_id()); + song->set_musicbrainz_album_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_OriginalAlbumId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_original_album_id()); + song->set_musicbrainz_original_album_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_TrackId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_track_id()); + song->set_musicbrainz_track_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_DiscId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_disc_id()); + song->set_musicbrainz_disc_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_ReleaseGroupId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_release_group_id()); + song->set_musicbrainz_release_group_id(frame_field_list.back()); } if (frame->description() == kID3v2_MusicBrainz_WorkId) { - AssignTagLibStringToStdString(frame_field_list.back(), song->mutable_musicbrainz_work_id()); + song->set_musicbrainz_work_id(frame_field_list.back()); } } } @@ -624,15 +634,15 @@ void TagReaderTagLib::ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QSt } -void TagReaderTagLib::ParseVorbisComments(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const { +void TagReaderTagLib::ParseVorbisComments(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, Song *song) const { - if (map.contains(kVorbisComment_Composer)) AssignTagLibStringToStdString(map[kVorbisComment_Composer].front(), song->mutable_composer()); - if (map.contains(kVorbisComment_Performer)) AssignTagLibStringToStdString(map[kVorbisComment_Performer].front(), song->mutable_performer()); - if (map.contains(kVorbisComment_Grouping2)) AssignTagLibStringToStdString(map[kVorbisComment_Grouping2].front(), song->mutable_grouping()); - if (map.contains(kVorbisComment_Grouping1)) AssignTagLibStringToStdString(map[kVorbisComment_Grouping1].front(), song->mutable_grouping()); + if (map.contains(kVorbisComment_Composer)) song->set_composer(map[kVorbisComment_Composer].front()); + if (map.contains(kVorbisComment_Performer)) song->set_performer(map[kVorbisComment_Performer].front()); + if (map.contains(kVorbisComment_Grouping2)) song->set_grouping(map[kVorbisComment_Grouping2].front()); + if (map.contains(kVorbisComment_Grouping1)) song->set_grouping(map[kVorbisComment_Grouping1].front()); - if (map.contains(kVorbisComment_AlbumArtist1)) AssignTagLibStringToStdString(map[kVorbisComment_AlbumArtist1].front(), song->mutable_albumartist()); - else if (map.contains(kVorbisComment_AlbumArtist2)) AssignTagLibStringToStdString(map[kVorbisComment_AlbumArtist2].front(), song->mutable_albumartist()); + if (map.contains(kVorbisComment_AlbumArtist1)) song->set_albumartist(map[kVorbisComment_AlbumArtist1].front()); + else if (map.contains(kVorbisComment_AlbumArtist2)) song->set_albumartist(map[kVorbisComment_AlbumArtist2].front()); if (map.contains(kVorbisComment_OriginalYear1)) song->set_originalyear(TagLibStringToQString(map[kVorbisComment_OriginalYear1].front()).left(4).toInt()); else if (map.contains(kVorbisComment_OriginalYear2)) song->set_originalyear(TagLibStringToQString(map[kVorbisComment_OriginalYear2].front()).toInt()); @@ -647,32 +657,32 @@ void TagReaderTagLib::ParseVorbisComments(const TagLib::Ogg::FieldListMap &map, } if (map.contains(kVorbisComment_FMPS_Rating) && song->rating() <= 0) song->set_rating(TagLibStringToQString(map[kVorbisComment_FMPS_Rating].front()).trimmed().toFloat()); - if (map.contains(kVorbisComment_Lyrics)) AssignTagLibStringToStdString(map[kVorbisComment_Lyrics].front(), song->mutable_lyrics()); - else if (map.contains(kVorbisComment_UnsyncedLyrics)) AssignTagLibStringToStdString(map[kVorbisComment_UnsyncedLyrics].front(), song->mutable_lyrics()); + if (map.contains(kVorbisComment_Lyrics)) song->set_lyrics(map[kVorbisComment_Lyrics].front()); + else if (map.contains(kVorbisComment_UnsyncedLyrics)) song->set_lyrics(map[kVorbisComment_UnsyncedLyrics].front()); - if (map.contains(kVorbisComment_AcoustId)) AssignTagLibStringToStdString(map[kVorbisComment_AcoustId].front(), song->mutable_acoustid_id()); - if (map.contains(kVorbisComment_AcoustId_Fingerprint)) AssignTagLibStringToStdString(map[kVorbisComment_AcoustId_Fingerprint].front(), song->mutable_acoustid_fingerprint()); + if (map.contains(kVorbisComment_AcoustId)) song->set_acoustid_id(map[kVorbisComment_AcoustId].front()); + if (map.contains(kVorbisComment_AcoustId_Fingerprint)) song->set_acoustid_fingerprint(map[kVorbisComment_AcoustId_Fingerprint].front()); - if (map.contains(kVorbisComment_MusicBrainz_AlbumArtistId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_AlbumArtistId].front(), song->mutable_musicbrainz_album_artist_id()); - if (map.contains(kVorbisComment_MusicBrainz_ArtistId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_ArtistId].front(), song->mutable_musicbrainz_artist_id()); - if (map.contains(kVorbisComment_MusicBrainz_OriginalArtistId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_OriginalArtistId].front(), song->mutable_musicbrainz_original_artist_id()); - if (map.contains(kVorbisComment_MusicBrainz_AlbumId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_AlbumId].front(), song->mutable_musicbrainz_album_id()); - if (map.contains(kVorbisComment_MusicBrainz_OriginalAlbumId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_OriginalAlbumId].front(), song->mutable_musicbrainz_original_album_id()); - if (map.contains(kVorbisComment_MusicBrainz_TackId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_TackId].front(), song->mutable_musicbrainz_recording_id()); - if (map.contains(kVorbisComment_MusicBrainz_ReleaseTrackId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_ReleaseTrackId].front(), song->mutable_musicbrainz_track_id()); - if (map.contains(kVorbisComment_MusicBrainz_DiscId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_DiscId].front(), song->mutable_musicbrainz_disc_id()); - if (map.contains(kVorbisComment_MusicBrainz_ReleaseGroupId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_ReleaseGroupId].front(), song->mutable_musicbrainz_release_group_id()); - if (map.contains(kVorbisComment_MusicBrainz_WorkId)) AssignTagLibStringToStdString(map[kVorbisComment_MusicBrainz_WorkId].front(), song->mutable_musicbrainz_work_id()); + if (map.contains(kVorbisComment_MusicBrainz_AlbumArtistId)) song->set_musicbrainz_album_artist_id(map[kVorbisComment_MusicBrainz_AlbumArtistId].front()); + if (map.contains(kVorbisComment_MusicBrainz_ArtistId)) song->set_musicbrainz_artist_id(map[kVorbisComment_MusicBrainz_ArtistId].front()); + if (map.contains(kVorbisComment_MusicBrainz_OriginalArtistId)) song->set_musicbrainz_original_artist_id(map[kVorbisComment_MusicBrainz_OriginalArtistId].front()); + if (map.contains(kVorbisComment_MusicBrainz_AlbumId)) song->set_musicbrainz_album_id(map[kVorbisComment_MusicBrainz_AlbumId].front()); + if (map.contains(kVorbisComment_MusicBrainz_OriginalAlbumId)) song->set_musicbrainz_original_album_id(map[kVorbisComment_MusicBrainz_OriginalAlbumId].front()); + if (map.contains(kVorbisComment_MusicBrainz_TackId)) song->set_musicbrainz_recording_id(map[kVorbisComment_MusicBrainz_TackId].front()); + if (map.contains(kVorbisComment_MusicBrainz_ReleaseTrackId)) song->set_musicbrainz_track_id(map[kVorbisComment_MusicBrainz_ReleaseTrackId].front()); + if (map.contains(kVorbisComment_MusicBrainz_DiscId)) song->set_musicbrainz_disc_id(map[kVorbisComment_MusicBrainz_DiscId].front()); + if (map.contains(kVorbisComment_MusicBrainz_ReleaseGroupId)) song->set_musicbrainz_release_group_id(map[kVorbisComment_MusicBrainz_ReleaseGroupId].front()); + if (map.contains(kVorbisComment_MusicBrainz_WorkId)) song->set_musicbrainz_work_id(map[kVorbisComment_MusicBrainz_WorkId].front()); } -void TagReaderTagLib::ParseAPETags(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const { +void TagReaderTagLib::ParseAPETags(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, Song *song) const { TagLib::APE::ItemListMap::ConstIterator it = map.find(kAPE_AlbumArtist); if (it != map.end()) { TagLib::StringList album_artists = it->second.values(); if (!album_artists.isEmpty()) { - AssignTagLibStringToStdString(album_artists.front(), song->mutable_albumartist()); + song->set_albumartist(album_artists.front()); } } @@ -686,19 +696,19 @@ void TagReaderTagLib::ParseAPETags(const TagLib::APE::ItemListMap &map, QString } if (map.contains(kAPE_Performer)) { - AssignTagLibStringToStdString(map[kAPE_Performer].values().toString(", "), song->mutable_performer()); + song->set_performer(map[kAPE_Performer].values().toString(", ")); } if (map.contains(kAPE_Composer)) { - AssignTagLibStringToStdString(map[kAPE_Composer].values().toString(", "), song->mutable_composer()); + song->set_composer(map[kAPE_Composer].values().toString(", ")); } if (map.contains(kAPE_Grouping)) { - AssignTagLibStringToStdString(map[kAPE_Grouping].values().toString(" "), song->mutable_grouping()); + song->set_grouping(map[kAPE_Grouping].values().toString(" ")); } if (map.contains(kAPE_Lyrics)) { - AssignTagLibStringToStdString(map[kAPE_Lyrics].toString(), song->mutable_lyrics()); + song->set_lyrics(map[kAPE_Lyrics].toString()); } if (map.contains(kAPE_FMPS_Playcount)) { @@ -715,23 +725,23 @@ void TagReaderTagLib::ParseAPETags(const TagLib::APE::ItemListMap &map, QString } } - if (map.contains(kAPE_AcoustId)) AssignTagLibStringToStdString(map[kAPE_AcoustId].toString(), song->mutable_acoustid_id()); - if (map.contains(kAPE_AcoustId_Fingerprint)) AssignTagLibStringToStdString(map[kAPE_AcoustId_Fingerprint].toString(), song->mutable_acoustid_fingerprint()); + if (map.contains(kAPE_AcoustId)) song->set_acoustid_id(map[kAPE_AcoustId].toString()); + if (map.contains(kAPE_AcoustId_Fingerprint)) song->set_acoustid_fingerprint(map[kAPE_AcoustId_Fingerprint].toString()); - if (map.contains(kAPE_MusicBrainz_AlbumArtistId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_AlbumArtistId].toString(), song->mutable_musicbrainz_album_artist_id()); - if (map.contains(kAPE_MusicBrainz_ArtistId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_ArtistId].toString(), song->mutable_musicbrainz_artist_id()); - if (map.contains(kAPE_MusicBrainz_OriginalArtistId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_OriginalArtistId].toString(), song->mutable_musicbrainz_original_artist_id()); - if (map.contains(kAPE_MusicBrainz_AlbumId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_AlbumId].toString(), song->mutable_musicbrainz_album_id()); - if (map.contains(kAPE_MusicBrainz_OriginalAlbumId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_OriginalAlbumId].toString(), song->mutable_musicbrainz_original_album_id()); - if (map.contains(kAPE_MusicBrainz_TackId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_TackId].toString(), song->mutable_musicbrainz_recording_id()); - if (map.contains(kAPE_MusicBrainz_ReleaseTrackId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_ReleaseTrackId].toString(), song->mutable_musicbrainz_track_id()); - if (map.contains(kAPE_MusicBrainz_DiscId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_DiscId].toString(), song->mutable_musicbrainz_disc_id()); - if (map.contains(kAPE_MusicBrainz_ReleaseGroupId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_ReleaseGroupId].toString(), song->mutable_musicbrainz_release_group_id()); - if (map.contains(kAPE_MusicBrainz_WorkId)) AssignTagLibStringToStdString(map[kAPE_MusicBrainz_WorkId].toString(), song->mutable_musicbrainz_work_id()); + if (map.contains(kAPE_MusicBrainz_AlbumArtistId)) song->set_musicbrainz_album_artist_id(map[kAPE_MusicBrainz_AlbumArtistId].toString()); + if (map.contains(kAPE_MusicBrainz_ArtistId)) song->set_musicbrainz_artist_id(map[kAPE_MusicBrainz_ArtistId].toString()); + if (map.contains(kAPE_MusicBrainz_OriginalArtistId)) song->set_musicbrainz_original_artist_id(map[kAPE_MusicBrainz_OriginalArtistId].toString()); + if (map.contains(kAPE_MusicBrainz_AlbumId)) song->set_musicbrainz_album_id(map[kAPE_MusicBrainz_AlbumId].toString()); + if (map.contains(kAPE_MusicBrainz_OriginalAlbumId)) song->set_musicbrainz_original_album_id(map[kAPE_MusicBrainz_OriginalAlbumId].toString()); + if (map.contains(kAPE_MusicBrainz_TackId)) song->set_musicbrainz_recording_id(map[kAPE_MusicBrainz_TackId].toString()); + if (map.contains(kAPE_MusicBrainz_ReleaseTrackId)) song->set_musicbrainz_track_id(map[kAPE_MusicBrainz_ReleaseTrackId].toString()); + if (map.contains(kAPE_MusicBrainz_DiscId)) song->set_musicbrainz_disc_id(map[kAPE_MusicBrainz_DiscId].toString()); + if (map.contains(kAPE_MusicBrainz_ReleaseGroupId)) song->set_musicbrainz_release_group_id(map[kAPE_MusicBrainz_ReleaseGroupId].toString()); + if (map.contains(kAPE_MusicBrainz_WorkId)) song->set_musicbrainz_work_id(map[kAPE_MusicBrainz_WorkId].toString()); } -void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const { +void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString *compilation, Song *song) const { Q_UNUSED(compilation); @@ -739,7 +749,7 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString if (tag->item(kMP4_AlbumArtist).isValid()) { const TagLib::StringList album_artists = tag->item(kMP4_AlbumArtist).toStringList(); if (!album_artists.isEmpty()) { - AssignTagLibStringToStdString(album_artists.front(), song->mutable_albumartist()); + song->set_albumartist(album_artists.front()); } } @@ -753,13 +763,13 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString } if (tag->item(kMP4_Composer).isValid()) { - AssignTagLibStringToStdString(tag->item(kMP4_Composer).toStringList().toString(", "), song->mutable_composer()); + song->set_composer(tag->item(kMP4_Composer).toStringList().toString(", ")); } if (tag->item(kMP4_Grouping).isValid()) { - AssignTagLibStringToStdString(tag->item(kMP4_Grouping).toStringList().toString(" "), song->mutable_grouping()); + song->set_grouping(tag->item(kMP4_Grouping).toStringList().toString(" ")); } if (tag->item(kMP4_Lyrics).isValid()) { - AssignTagLibStringToStdString(tag->item(kMP4_Lyrics).toStringList().toString(" "), song->mutable_lyrics()); + song->set_lyrics(tag->item(kMP4_Lyrics).toStringList().toString(" ")); } if (tag->item(kMP4_OriginalYear).isValid()) { @@ -790,48 +800,49 @@ void TagReaderTagLib::ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString } } - AssignTagLibStringToStdString(tag->comment(), song->mutable_comment()); + song->set_comment(tag->comment()); if (tag->contains(kMP4_AcoustId)) { - AssignTagLibStringToStdString(tag->item(kMP4_AcoustId).toStringList().toString(), song->mutable_acoustid_id()); + song->set_acoustid_id(tag->item(kMP4_AcoustId).toStringList().toString()); } if (tag->contains(kMP4_AcoustId_Fingerprint)) { - AssignTagLibStringToStdString(tag->item(kMP4_AcoustId_Fingerprint).toStringList().toString(), song->mutable_acoustid_fingerprint()); + song->set_acoustid_fingerprint(tag->item(kMP4_AcoustId_Fingerprint).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_AlbumArtistId)) { - AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_AlbumArtistId).toStringList()), song->mutable_musicbrainz_album_artist_id()); + song->set_musicbrainz_album_artist_id(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_AlbumArtistId).toStringList())); } if (tag->contains(kMP4_MusicBrainz_ArtistId)) { - AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_ArtistId).toStringList()), song->mutable_musicbrainz_artist_id()); + song->set_musicbrainz_artist_id(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_ArtistId).toStringList())); } if (tag->contains(kMP4_MusicBrainz_OriginalArtistId)) { - AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_OriginalArtistId).toStringList()), song->mutable_musicbrainz_original_artist_id()); + song->set_musicbrainz_original_artist_id(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_OriginalArtistId).toStringList())); } if (tag->contains(kMP4_MusicBrainz_AlbumId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_AlbumId).toStringList().toString(), song->mutable_musicbrainz_album_id()); + song->set_musicbrainz_album_id(tag->item(kMP4_MusicBrainz_AlbumId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_OriginalAlbumId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_OriginalAlbumId).toStringList().toString(), song->mutable_musicbrainz_original_album_id()); + song->set_musicbrainz_original_album_id(tag->item(kMP4_MusicBrainz_OriginalAlbumId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_RecordingId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_RecordingId).toStringList().toString(), song->mutable_musicbrainz_recording_id()); + song->set_musicbrainz_recording_id(tag->item(kMP4_MusicBrainz_RecordingId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_TrackId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_TrackId).toStringList().toString(), song->mutable_musicbrainz_track_id()); + song->set_musicbrainz_track_id(tag->item(kMP4_MusicBrainz_TrackId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_DiscId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_DiscId).toStringList().toString(), song->mutable_musicbrainz_disc_id()); + song->set_musicbrainz_disc_id(tag->item(kMP4_MusicBrainz_DiscId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_ReleaseGroupId)) { - AssignTagLibStringToStdString(tag->item(kMP4_MusicBrainz_ReleaseGroupId).toStringList().toString(), song->mutable_musicbrainz_release_group_id()); + song->set_musicbrainz_release_group_id(tag->item(kMP4_MusicBrainz_ReleaseGroupId).toStringList().toString()); } if (tag->contains(kMP4_MusicBrainz_WorkId)) { - AssignTagLibStringToStdString(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_WorkId).toStringList()), song->mutable_musicbrainz_work_id()); + song->set_musicbrainz_work_id(TagLibStringListToSlashSeparatedString(tag->item(kMP4_MusicBrainz_WorkId).toStringList())); } } -void TagReaderTagLib::ParseASFTags(TagLib::ASF::Tag *tag, QString *disc, QString *compilation, spb::tagreader::SongMetadata *song) const { + +void TagReaderTagLib::ParseASFTags(TagLib::ASF::Tag *tag, QString *disc, QString *compilation, Song *song) const { Q_UNUSED(disc); Q_UNUSED(compilation); @@ -897,64 +908,66 @@ void TagReaderTagLib::ParseASFTags(TagLib::ASF::Tag *tag, QString *disc, QString } -void TagReaderTagLib::ParseASFAttribute(const TagLib::ASF::AttributeListMap &attributes_map, const char *attribute, std::string *str) const { +void TagReaderTagLib::ParseASFAttribute(const TagLib::ASF::AttributeListMap &attributes_map, const char *attribute, QString *str) const { if (attributes_map.contains(attribute)) { const TagLib::ASF::AttributeList &attributes = attributes_map[attribute]; if (!attributes.isEmpty()) { - AssignTagLibStringToStdString(attributes.front().toString(), str); + *str = TagLibStringToQString(attributes.front().toString()); } } } -TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const spb::tagreader::WriteFileRequest &request) const { +TagReaderResult TagReaderTagLib::WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } if (!QFile::exists(filename)) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } - const spb::tagreader::SongMetadata &song = request.metadata(); - const bool save_tags = request.has_save_tags() && request.save_tags(); - const bool save_playcount = request.has_save_playcount() && request.save_playcount(); - const bool save_rating = request.has_save_rating() && request.save_rating(); - const bool save_cover = request.has_save_cover() && request.save_cover(); + const bool save_tags = save_tags_options.testFlag(SaveTagsOption::Tags); + const bool save_playcount = save_tags_options.testFlag(SaveTagsOption::Playcount); + const bool save_rating = save_tags_options.testFlag(SaveTagsOption::Rating); + const bool save_cover = save_tags_options.testFlag(SaveTagsOption::Cover); - QStringList save_tags_options; + QStringList save_tags_options_list; if (save_tags) { - save_tags_options << QStringLiteral("tags"); + save_tags_options_list << u"tags"_s; } if (save_playcount) { - save_tags_options << QStringLiteral("playcount"); + save_tags_options_list << u"playcount"_s; } if (save_rating) { - save_tags_options << QStringLiteral("rating"); + save_tags_options_list << u"rating"_s; } if (save_cover) { - save_tags_options << QStringLiteral("embedded cover"); + save_tags_options_list << u"embedded cover"_s; } - qLog(Debug) << "Saving" << save_tags_options.join(", "_L1) << "to" << filename; + qLog(Debug) << "Saving" << save_tags_options_list.join(", "_L1) << "to" << filename; - const Cover cover = LoadCoverFromRequest(filename, request); + AlbumCoverTagData cover; + if (save_cover) { + cover = LoadAlbumCoverTagData(filename, save_tag_cover_data); + } - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } if (save_tags) { - fileref->tag()->setTitle(song.title().empty() ? TagLib::String() : StdStringToTagLibString(song.title())); - fileref->tag()->setArtist(song.artist().empty() ? TagLib::String() : StdStringToTagLibString(song.artist())); - fileref->tag()->setAlbum(song.album().empty() ? TagLib::String() : StdStringToTagLibString(song.album())); - fileref->tag()->setGenre(song.genre().empty() ? TagLib::String() : StdStringToTagLibString(song.genre())); - fileref->tag()->setComment(song.comment().empty() ? TagLib::String() : StdStringToTagLibString(song.comment())); + fileref->tag()->setTitle(song.title().isEmpty() ? TagLib::String() : QStringToTagLibString(song.title())); + fileref->tag()->setArtist(song.artist().isEmpty() ? TagLib::String() : QStringToTagLibString(song.artist())); + fileref->tag()->setAlbum(song.album().isEmpty() ? TagLib::String() : QStringToTagLibString(song.album())); + fileref->tag()->setGenre(song.genre().isEmpty() ? TagLib::String() : QStringToTagLibString(song.genre())); + fileref->tag()->setComment(song.comment().isEmpty() ? TagLib::String() : QStringToTagLibString(song.comment())); fileref->tag()->setYear(song.year() <= 0 ? 0 : song.year()); fileref->tag()->setTrack(song.track() <= 0 ? 0 : song.track()); } @@ -974,7 +987,7 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const SetRating(vorbis_comment, song.rating()); } if (save_cover) { - SetEmbeddedArt(file_flac, vorbis_comment, cover.data, cover.mime_type); + SetEmbeddedCover(file_flac, vorbis_comment, cover.data, cover.mimetype); } } } @@ -1037,7 +1050,7 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const SetRating(tag, song.rating()); } if (save_cover) { - SetEmbeddedArt(tag, cover.data, cover.mime_type); + SetEmbeddedCover(tag, cover.data, cover.mimetype); } } } @@ -1047,10 +1060,10 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const if (tag) { if (save_tags) { tag->setItem(kMP4_Disc, TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0)); - tag->setItem(kMP4_Composer, TagLib::StringList(TagLib::String(song.composer(), TagLib::String::UTF8))); - tag->setItem(kMP4_Grouping, TagLib::StringList(TagLib::String(song.grouping(), TagLib::String::UTF8))); - tag->setItem(kMP4_Lyrics, TagLib::StringList(TagLib::String(song.lyrics(), TagLib::String::UTF8))); - tag->setItem(kMP4_AlbumArtist, TagLib::StringList(TagLib::String(song.albumartist(), TagLib::String::UTF8))); + tag->setItem(kMP4_Composer, TagLib::StringList(QStringToTagLibString(song.composer()))); + tag->setItem(kMP4_Grouping, TagLib::StringList(QStringToTagLibString(song.grouping()))); + tag->setItem(kMP4_Lyrics, TagLib::StringList(QStringToTagLibString(song.lyrics()))); + tag->setItem(kMP4_AlbumArtist, TagLib::StringList(QStringToTagLibString(song.albumartist()))); tag->setItem(kMP4_Compilation, TagLib::MP4::Item(song.compilation())); } if (save_playcount) { @@ -1060,7 +1073,7 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const SetRating(tag, song.rating()); } if (save_cover) { - SetEmbeddedArt(file_mp4, tag, cover.data, cover.mime_type); + SetEmbeddedCover(file_mp4, tag, cover.data, cover.mimetype); } } } @@ -1078,7 +1091,7 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const SetRating(tag, song.rating()); } if (save_cover) { - SetEmbeddedArt(tag, cover.data, cover.mime_type); + SetEmbeddedCover(tag, cover.data, cover.mimetype); } } } @@ -1104,7 +1117,7 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const SetRating(vorbis_comment, song.rating()); } if (save_cover) { - SetEmbeddedArt(vorbis_comment, cover.data, cover.mime_type); + SetEmbeddedCover(vorbis_comment, cover.data, cover.mimetype); } } } @@ -1118,32 +1131,25 @@ TagReaderBase::Result TagReaderTagLib::WriteFile(const QString &filename, const } #endif // Q_OS_LINUX - return success ? Result(Result::ErrorCode::Success) : Result(Result::ErrorCode::FileSaveError); + return success ? TagReaderResult(TagReaderResult::ErrorCode::Success) : TagReaderResult(TagReaderResult::ErrorCode::FileSaveError); } -void TagReaderTagLib::SetID3v2Tag(TagLib::ID3v2::Tag *tag, const spb::tagreader::SongMetadata &song) const { +void TagReaderTagLib::SetID3v2Tag(TagLib::ID3v2::Tag *tag, const Song &song) const { SetTextFrame(kID3v2_Disc, song.disc() <= 0 ? QString() : QString::number(song.disc()), tag); - SetTextFrame(kID3v2_Composer, song.composer().empty() ? std::string() : song.composer(), tag); - SetTextFrame(kID3v2_Grouping, song.grouping().empty() ? std::string() : song.grouping(), tag); - SetTextFrame(kID3v2_Performer, song.performer().empty() ? std::string() : song.performer(), tag); + SetTextFrame(kID3v2_Composer, song.composer().isEmpty() ? QString() : song.composer(), tag); + SetTextFrame(kID3v2_Grouping, song.grouping().isEmpty() ? QString() : song.grouping(), tag); + SetTextFrame(kID3v2_Performer, song.performer().isEmpty() ? QString() : song.performer(), tag); // Skip TPE1 (which is the artist) here because we already set it - SetTextFrame(kID3v2_AlbumArtist, song.albumartist().empty() ? std::string() : song.albumartist(), tag); + SetTextFrame(kID3v2_AlbumArtist, song.albumartist().isEmpty() ? QString() : song.albumartist(), tag); SetTextFrame(kID3v2_Compilation, song.compilation() ? QString::number(1) : QString(), tag); - SetUnsyncLyricsFrame(song.lyrics().empty() ? std::string() : song.lyrics(), tag); + SetUnsyncLyricsFrame(song.lyrics().isEmpty() ? QString() : song.lyrics(), tag); } void TagReaderTagLib::SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const { - const QByteArray utf8(value.toUtf8()); - SetTextFrame(id, std::string(utf8.constData(), utf8.length()), tag); - -} - -void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const { - const TagLib::ByteVector id_vector(id); QList frames_buffer; @@ -1153,7 +1159,7 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag tag->removeFrame(tag->frameListMap()[id_vector].front()); } - if (value.empty()) return; + if (value.isEmpty()) return; // If no frames stored create empty frame if (frames_buffer.isEmpty()) { @@ -1165,9 +1171,9 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag for (int i = 0; i < frames_buffer.size(); ++i) { TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(i)); if (i == 0) { - frame->setText(StdStringToTagLibString(value)); + frame->setText(QStringToTagLibString(value)); } - // add frame takes ownership and clears the memory + // Add frame takes ownership and clears the memory tag->addFrame(frame); } @@ -1175,15 +1181,7 @@ void TagReaderTagLib::SetTextFrame(const char *id, const std::string &value, Tag void TagReaderTagLib::SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const { - const QByteArray descr_utf8(description.toUtf8()); - const QByteArray value_utf8(value.toUtf8()); - SetUserTextFrame(std::string(descr_utf8.constData(), descr_utf8.length()), std::string(value_utf8.constData(), value_utf8.length()), tag); - -} - -void TagReaderTagLib::SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const { - - const TagLib::String t_description = StdStringToTagLibString(description); + const TagLib::String t_description = QStringToTagLibString(description); TagLib::ID3v2::UserTextIdentificationFrame *frame = TagLib::ID3v2::UserTextIdentificationFrame::find(tag, t_description); if (frame) { tag->removeFrame(frame); @@ -1192,12 +1190,12 @@ void TagReaderTagLib::SetUserTextFrame(const std::string &description, const std // Create and add a new frame frame = new TagLib::ID3v2::UserTextIdentificationFrame(TagLib::String::UTF8); frame->setDescription(t_description); - frame->setText(StdStringToTagLibString(value)); + frame->setText(QStringToTagLibString(value)); tag->addFrame(frame); } -void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3v2::Tag *tag) const { +void TagReaderTagLib::SetUnsyncLyricsFrame(const QString &value, TagLib::ID3v2::Tag *tag) const { TagLib::ByteVector id_vector(kID3v2_UnsychronizedLyrics); QList frames_buffer; @@ -1208,7 +1206,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3 tag->removeFrame(tag->frameListMap()[id_vector].front()); } - if (value.empty()) return; + if (value.isEmpty()) return; // If no frames stored create empty frame if (frames_buffer.isEmpty()) { @@ -1221,7 +1219,7 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3 for (int i = 0; i < frames_buffer.size(); ++i) { TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(i)); if (i == 0) { - frame->setText(StdStringToTagLibString(value)); + frame->setText(QStringToTagLibString(value)); } // add frame takes ownership and clears the memory tag->addFrame(frame); @@ -1229,37 +1227,37 @@ void TagReaderTagLib::SetUnsyncLyricsFrame(const std::string &value, TagLib::ID3 } -void TagReaderTagLib::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comment, const spb::tagreader::SongMetadata &song) const { +void TagReaderTagLib::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comment, const Song &song) const { - vorbis_comment->addField(kVorbisComment_Composer, StdStringToTagLibString(song.composer()), true); - vorbis_comment->addField(kVorbisComment_Performer, StdStringToTagLibString(song.performer()), true); - vorbis_comment->addField(kVorbisComment_Grouping1, StdStringToTagLibString(song.grouping()), true); + vorbis_comment->addField(kVorbisComment_Composer, QStringToTagLibString(song.composer()), true); + vorbis_comment->addField(kVorbisComment_Performer, QStringToTagLibString(song.performer()), true); + vorbis_comment->addField(kVorbisComment_Grouping1, QStringToTagLibString(song.grouping()), true); vorbis_comment->addField(kVorbisComment_Disc, QStringToTagLibString(song.disc() <= 0 ? QString() : QString::number(song.disc())), true); - vorbis_comment->addField(kVorbisComment_Compilation, QStringToTagLibString(song.compilation() ? QStringLiteral("1") : QString()), true); + vorbis_comment->addField(kVorbisComment_Compilation, QStringToTagLibString(song.compilation() ? u"1"_s : QString()), true); // Try to be coherent, the two forms are used but the first one is preferred - vorbis_comment->addField(kVorbisComment_AlbumArtist1, StdStringToTagLibString(song.albumartist()), true); + vorbis_comment->addField(kVorbisComment_AlbumArtist1, QStringToTagLibString(song.albumartist()), true); vorbis_comment->removeFields(kVorbisComment_AlbumArtist2); - vorbis_comment->addField(kVorbisComment_Lyrics, StdStringToTagLibString(song.lyrics()), true); + vorbis_comment->addField(kVorbisComment_Lyrics, QStringToTagLibString(song.lyrics()), true); vorbis_comment->removeFields(kVorbisComment_UnsyncedLyrics); } -void TagReaderTagLib::SetAPETag(TagLib::APE::Tag *tag, const spb::tagreader::SongMetadata &song) const { +void TagReaderTagLib::SetAPETag(TagLib::APE::Tag *tag, const Song &song) const { - tag->setItem(kAPE_AlbumArtist, TagLib::APE::Item(kAPE_AlbumArtist, TagLib::StringList(song.albumartist().c_str()))); + tag->setItem(kAPE_AlbumArtist, TagLib::APE::Item(kAPE_AlbumArtist, TagLib::StringList(QStringToTagLibString(song.albumartist())))); tag->addValue(kAPE_Disc, QStringToTagLibString(song.disc() <= 0 ? QString() : QString::number(song.disc())), true); - tag->setItem(kAPE_Composer, TagLib::APE::Item(kAPE_Composer, TagLib::StringList(song.composer().c_str()))); - tag->setItem(kAPE_Grouping, TagLib::APE::Item(kAPE_Grouping, TagLib::StringList(song.grouping().c_str()))); - tag->setItem(kAPE_Performer, TagLib::APE::Item(kAPE_Performer, TagLib::StringList(song.performer().c_str()))); - tag->setItem(kAPE_Lyrics, TagLib::APE::Item(kAPE_Lyrics, TagLib::String(song.lyrics()))); + tag->setItem(kAPE_Composer, TagLib::APE::Item(kAPE_Composer, TagLib::StringList(QStringToTagLibString(song.composer())))); + tag->setItem(kAPE_Grouping, TagLib::APE::Item(kAPE_Grouping, TagLib::StringList(QStringToTagLibString(song.grouping())))); + tag->setItem(kAPE_Performer, TagLib::APE::Item(kAPE_Performer, TagLib::StringList(QStringToTagLibString(song.performer())))); + tag->setItem(kAPE_Lyrics, TagLib::APE::Item(kAPE_Lyrics, QStringToTagLibString(song.lyrics()))); tag->addValue(kAPE_Compilation, QStringToTagLibString(song.compilation() ? QString::number(1) : QString()), true); } -void TagReaderTagLib::SetASFTag(TagLib::ASF::Tag *tag, const spb::tagreader::SongMetadata &song) const { +void TagReaderTagLib::SetASFTag(TagLib::ASF::Tag *tag, const Song &song) const { SetAsfAttribute(tag, kASF_AlbumArtist, song.albumartist()); SetAsfAttribute(tag, kASF_Composer, song.composer()); @@ -1270,15 +1268,15 @@ void TagReaderTagLib::SetASFTag(TagLib::ASF::Tag *tag, const spb::tagreader::Son } -void TagReaderTagLib::SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const std::string &value) const { +void TagReaderTagLib::SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const QString &value) const { - if (value.empty()) { + if (value.isEmpty()) { if (tag->contains(attribute)) { tag->removeItem(attribute); } } else { - tag->addAttribute(attribute, StdStringToTagLibString(value)); + tag->addAttribute(attribute, QStringToTagLibString(value)); } } @@ -1296,23 +1294,23 @@ void TagReaderTagLib::SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribu } -TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, QByteArray &data) const { +TagReaderResult TagReaderTagLib::LoadEmbeddedCover(const QString &filename, QByteArray &data) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } if (!QFile::exists(filename)) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } - qLog(Debug) << "Loading art from" << filename; + qLog(Debug) << "Loading cover from" << filename; - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } // FLAC @@ -1324,7 +1322,7 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, if (picture->type() == TagLib::FLAC::Picture::FrontCover && picture->data().size() > 0) { data = QByteArray(picture->data().data(), picture->data().size()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1335,9 +1333,9 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, // WavPack if (TagLib::WavPack::File *wavpack_file = dynamic_cast(fileref->file())) { if (wavpack_file->APETag()) { - data = LoadEmbeddedAPEArt(wavpack_file->APETag()->itemListMap()); + data = LoadEmbeddedAPECover(wavpack_file->APETag()->itemListMap()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1345,9 +1343,9 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, // APE if (TagLib::APE::File *ape_file = dynamic_cast(fileref->file())) { if (ape_file->APETag()) { - data = LoadEmbeddedAPEArt(ape_file->APETag()->itemListMap()); + data = LoadEmbeddedAPECover(ape_file->APETag()->itemListMap()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1355,9 +1353,9 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, // MPC if (TagLib::MPC::File *mpc_file = dynamic_cast(fileref->file())) { if (mpc_file->APETag()) { - data = LoadEmbeddedAPEArt(mpc_file->APETag()->itemListMap()); + data = LoadEmbeddedAPECover(mpc_file->APETag()->itemListMap()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1372,7 +1370,7 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, if (picture->type() == TagLib::FLAC::Picture::FrontCover && picture->data().size() > 0) { data = QByteArray(picture->data().data(), picture->data().size()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1382,7 +1380,7 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, if (map.contains(kVorbisComment_CoverArt)) { data = QByteArray::fromBase64(map[kVorbisComment_CoverArt].toString().toCString()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } @@ -1393,14 +1391,14 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, if (file_mp3->ID3v2Tag()) { TagLib::ID3v2::FrameList apic_frames = file_mp3->ID3v2Tag()->frameListMap()[kID3v2_CoverArt]; if (apic_frames.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } TagLib::ID3v2::AttachedPictureFrame *picture = static_cast(apic_frames.front()); data = QByteArray(reinterpret_cast(picture->picture().data()), picture->picture().size()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } @@ -1416,17 +1414,17 @@ TagReaderBase::Result TagReaderTagLib::LoadEmbeddedArt(const QString &filename, const TagLib::MP4::CoverArt &art = art_list.front(); data = QByteArray(art.data().data(), art.data().size()); if (!data.isEmpty()) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } } } } - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } -QByteArray TagReaderTagLib::LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const { +QByteArray TagReaderTagLib::LoadEmbeddedAPECover(const TagLib::APE::ItemListMap &map) const { TagLib::APE::ItemListMap::ConstIterator it = map.find(kAPE_CoverArt); if (it != map.end()) { @@ -1442,7 +1440,7 @@ QByteArray TagReaderTagLib::LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &m } -void TagReaderTagLib::SetEmbeddedArt(TagLib::FLAC::File *flac_file, TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mime_type) const { +void TagReaderTagLib::SetEmbeddedCover(TagLib::FLAC::File *flac_file, TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mimetype) const { (void)vorbis_comment; @@ -1451,28 +1449,28 @@ void TagReaderTagLib::SetEmbeddedArt(TagLib::FLAC::File *flac_file, TagLib::Ogg: if (!data.isEmpty()) { TagLib::FLAC::Picture *picture = new TagLib::FLAC::Picture(); picture->setType(TagLib::FLAC::Picture::FrontCover); - picture->setMimeType(QStringToTagLibString(mime_type)); + picture->setMimeType(QStringToTagLibString(mimetype)); picture->setData(TagLib::ByteVector(data.constData(), data.size())); flac_file->addPicture(picture); } } -void TagReaderTagLib::SetEmbeddedArt(TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mime_type) const { +void TagReaderTagLib::SetEmbeddedCover(TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mimetype) const { vorbis_comment->removeAllPictures(); if (!data.isEmpty()) { TagLib::FLAC::Picture *picture = new TagLib::FLAC::Picture(); picture->setType(TagLib::FLAC::Picture::FrontCover); - picture->setMimeType(QStringToTagLibString(mime_type)); + picture->setMimeType(QStringToTagLibString(mimetype)); picture->setData(TagLib::ByteVector(data.constData(), data.size())); vorbis_comment->addPicture(picture); } } -void TagReaderTagLib::SetEmbeddedArt(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mime_type) const { +void TagReaderTagLib::SetEmbeddedCover(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mimetype) const { // Remove existing covers TagLib::ID3v2::FrameList apiclist = tag->frameListMap()[kID3v2_CoverArt]; @@ -1486,14 +1484,14 @@ void TagReaderTagLib::SetEmbeddedArt(TagLib::ID3v2::Tag *tag, const QByteArray & TagLib::ID3v2::AttachedPictureFrame *frontcover = nullptr; frontcover = new TagLib::ID3v2::AttachedPictureFrame(kID3v2_CoverArt); frontcover->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); - frontcover->setMimeType(QStringToTagLibString(mime_type)); + frontcover->setMimeType(QStringToTagLibString(mimetype)); frontcover->setPicture(TagLib::ByteVector(data.constData(), data.size())); tag->addFrame(frontcover); } } -void TagReaderTagLib::SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mime_type) const { +void TagReaderTagLib::SetEmbeddedCover(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mimetype) const { (void)aac_file; @@ -1503,10 +1501,10 @@ void TagReaderTagLib::SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::T } else { TagLib::MP4::CoverArt::Format cover_format = TagLib::MP4::CoverArt::Format::JPEG; - if (mime_type == "image/jpeg"_L1) { + if (mimetype == "image/jpeg"_L1) { cover_format = TagLib::MP4::CoverArt::Format::JPEG; } - else if (mime_type == "image/png"_L1) { + else if (mimetype == "image/png"_L1) { cover_format = TagLib::MP4::CoverArt::Format::PNG; } else { @@ -1518,45 +1516,45 @@ void TagReaderTagLib::SetEmbeddedArt(TagLib::MP4::File *aac_file, TagLib::MP4::T } -TagReaderBase::Result TagReaderTagLib::SaveEmbeddedArt(const QString &filename, const spb::tagreader::SaveEmbeddedArtRequest &request) const { +TagReaderResult TagReaderTagLib::SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } - qLog(Debug) << "Saving art to" << filename; + qLog(Debug) << "Saving cover to" << filename; if (!QFile::exists(filename)) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } - const Cover cover = LoadCoverFromRequest(filename, request); - - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } + const AlbumCoverTagData cover = LoadAlbumCoverTagData(filename, save_tag_cover_data); + // FLAC if (TagLib::FLAC::File *flac_file = dynamic_cast(fileref->file())) { TagLib::Ogg::XiphComment *vorbis_comment = flac_file->xiphComment(true); if (vorbis_comment) { - SetEmbeddedArt(flac_file, vorbis_comment, cover.data, cover.mime_type); + SetEmbeddedCover(flac_file, vorbis_comment, cover.data, cover.mimetype); } } // Ogg Vorbis / Opus / Speex else if (TagLib::Ogg::XiphComment *vorbis_comment = dynamic_cast(fileref->file()->tag())) { - SetEmbeddedArt(vorbis_comment, cover.data, cover.mime_type); + SetEmbeddedCover(vorbis_comment, cover.data, cover.mimetype); } // MP3 else if (TagLib::MPEG::File *file_mp3 = dynamic_cast(fileref->file())) { TagLib::ID3v2::Tag *tag = file_mp3->ID3v2Tag(); if (tag) { - SetEmbeddedArt(tag, cover.data, cover.mime_type); + SetEmbeddedCover(tag, cover.data, cover.mimetype); } } @@ -1564,14 +1562,14 @@ TagReaderBase::Result TagReaderTagLib::SaveEmbeddedArt(const QString &filename, else if (TagLib::MP4::File *aac_file = dynamic_cast(fileref->file())) { TagLib::MP4::Tag *tag = aac_file->tag(); if (tag) { - SetEmbeddedArt(aac_file, tag, cover.data, cover.mime_type); + SetEmbeddedCover(aac_file, tag, cover.data, cover.mimetype); } } // Not supported. else { qLog(Error) << "Saving embedded art is not supported for %1" << filename; - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } const bool success = fileref->file()->save(); @@ -1582,7 +1580,7 @@ TagReaderBase::Result TagReaderTagLib::SaveEmbeddedArt(const QString &filename, } #endif // Q_OS_LINUX - return success ? Result::ErrorCode::Success : Result::ErrorCode::FileSaveError; + return success ? TagReaderResult::ErrorCode::Success : TagReaderResult::ErrorCode::FileSaveError; } @@ -1658,23 +1656,23 @@ void TagReaderTagLib::SetPlaycount(TagLib::ASF::Tag *tag, const uint playcount) } -TagReaderBase::Result TagReaderTagLib::SaveSongPlaycountToFile(const QString &filename, const uint playcount) const { +TagReaderResult TagReaderTagLib::SaveSongPlaycount(const QString &filename, const uint playcount) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } qLog(Debug) << "Saving song playcount to" << filename; if (!QFile::exists(filename)) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } if (TagLib::FLAC::File *flac_file = dynamic_cast(fileref->file())) { @@ -1725,7 +1723,7 @@ TagReaderBase::Result TagReaderTagLib::SaveSongPlaycountToFile(const QString &fi } } else { - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } const bool success = fileref->save(); @@ -1736,7 +1734,7 @@ TagReaderBase::Result TagReaderTagLib::SaveSongPlaycountToFile(const QString &fi } #endif // Q_OS_LINUX - return success ? Result::ErrorCode::Success : Result::ErrorCode::FileSaveError; + return success ? TagReaderResult::ErrorCode::Success : TagReaderResult::ErrorCode::FileSaveError; } @@ -1784,27 +1782,27 @@ void TagReaderTagLib::SetRating(TagLib::ASF::Tag *tag, const float rating) const } -TagReaderBase::Result TagReaderTagLib::SaveSongRatingToFile(const QString &filename, const float rating) const { +TagReaderResult TagReaderTagLib::SaveSongRating(const QString &filename, const float rating) const { if (filename.isEmpty()) { - return Result::ErrorCode::FilenameMissing; + return TagReaderResult::ErrorCode::FilenameMissing; } qLog(Debug) << "Saving song rating to" << filename; if (!QFile::exists(filename)) { qLog(Error) << "File" << filename << "does not exist"; - return Result::ErrorCode::FileDoesNotExist; + return TagReaderResult::ErrorCode::FileDoesNotExist; } if (rating < 0) { - return Result::ErrorCode::Success; + return TagReaderResult::ErrorCode::Success; } - std::unique_ptr fileref(factory_->GetFileRef(filename)); + unique_ptr fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) { qLog(Error) << "TagLib could not open file" << filename; - return Result::ErrorCode::FileOpenError; + return TagReaderResult::ErrorCode::FileOpenError; } if (TagLib::FLAC::File *flac_file = dynamic_cast(fileref->file())) { @@ -1854,7 +1852,7 @@ TagReaderBase::Result TagReaderTagLib::SaveSongRatingToFile(const QString &filen } else { qLog(Error) << "Unsupported file for saving rating for" << filename; - return Result::ErrorCode::Unsupported; + return TagReaderResult::ErrorCode::Unsupported; } const bool success = fileref->save(); @@ -1869,7 +1867,7 @@ TagReaderBase::Result TagReaderTagLib::SaveSongRatingToFile(const QString &filen qLog(Error) << "TagLib hasn't been able to save file" << filename; } - return success ? Result::ErrorCode::Success : Result::ErrorCode::FileSaveError; + return success ? TagReaderResult::ErrorCode::Success : TagReaderResult::ErrorCode::FileSaveError; } diff --git a/src/tagreader/tagreadertaglib.h b/src/tagreader/tagreadertaglib.h new file mode 100644 index 000000000..fcefcf44c --- /dev/null +++ b/src/tagreader/tagreadertaglib.h @@ -0,0 +1,127 @@ +/* + * Strawberry Music Player + * Copyright 2013, David Sansome + * Copyright 2018-2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERTAGLIB_H +#define TAGREADERTAGLIB_H + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/song.h" + +#include "tagreaderbase.h" +#include "savetagcoverdata.h" + +#undef TStringToQString +#undef QStringToTString + +class FileRefFactory; + +class TagReaderTagLib : public TagReaderBase { + public: + explicit TagReaderTagLib(); + ~TagReaderTagLib() override; + + static inline TagLib::String QStringToTagLibString(const QString &s) { + return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8); + } + + static inline QString TagLibStringToQString(const TagLib::String &s) { + return QString::fromUtf8((s).toCString(true)); + } + + TagReaderResult IsMediaFile(const QString &filename) const override; + + TagReaderResult ReadFile(const QString &filename, Song *song) const override; + TagReaderResult WriteFile(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) const override; + + TagReaderResult LoadEmbeddedCover(const QString &filename, QByteArray &data) const override; + TagReaderResult SaveEmbeddedCover(const QString &filename, const SaveTagCoverData &save_tag_cover_data) const override; + + TagReaderResult SaveSongPlaycount(const QString &filename, const uint playcount) const override; + TagReaderResult SaveSongRating(const QString &filename, const float rating) const override; + + private: + Song::FileType GuessFileType(TagLib::FileRef *fileref) const; + + void ParseID3v2Tags(TagLib::ID3v2::Tag *tag, QString *disc, QString *compilation, Song *song) const; + void ParseVorbisComments(const TagLib::Ogg::FieldListMap &map, QString *disc, QString *compilation, Song *song) const; + void ParseAPETags(const TagLib::APE::ItemListMap &map, QString *disc, QString *compilation, Song *song) const; + void ParseMP4Tags(TagLib::MP4::Tag *tag, QString *disc, QString *compilation, Song *song) const; + void ParseASFTags(TagLib::ASF::Tag *tag, QString *disc, QString *compilation, Song *song) const; + void ParseASFAttribute(const TagLib::ASF::AttributeListMap &attributes_map, const char *attribute, QString *str) const; + + void SetID3v2Tag(TagLib::ID3v2::Tag *tag, const Song &song) const; + void SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const; + void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const; + void SetUnsyncLyricsFrame(const QString &value, TagLib::ID3v2::Tag *tag) const; + + void SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comment, const Song &song) const; + void SetAPETag(TagLib::APE::Tag *tag, const Song &song) const; + void SetASFTag(TagLib::ASF::Tag *tag, const Song &song) const; + void SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const QString &value) const; + void SetAsfAttribute(TagLib::ASF::Tag *tag, const char *attribute, const int value) const; + + QByteArray LoadEmbeddedAPECover(const TagLib::APE::ItemListMap &map) const; + + static TagLib::ID3v2::PopularimeterFrame *GetPOPMFrameFromTag(TagLib::ID3v2::Tag *tag); + + void SetPlaycount(TagLib::Ogg::XiphComment *vorbis_comment, const uint playcount) const; + void SetPlaycount(TagLib::APE::Tag *tag, const uint playcount) const; + void SetPlaycount(TagLib::ID3v2::Tag *tag, const uint playcount) const; + void SetPlaycount(TagLib::MP4::Tag *tag, const uint playcount) const; + void SetPlaycount(TagLib::ASF::Tag *tag, const uint playcount) const; + + void SetRating(TagLib::Ogg::XiphComment *vorbis_comment, const float rating) const; + void SetRating(TagLib::APE::Tag *tag, const float rating) const; + void SetRating(TagLib::ID3v2::Tag *tag, const float rating) const; + void SetRating(TagLib::MP4::Tag *tag, const float rating) const; + void SetRating(TagLib::ASF::Tag *tag, const float rating) const; + + void SetEmbeddedCover(TagLib::FLAC::File *flac_file, TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mimetype) const; + void SetEmbeddedCover(TagLib::Ogg::XiphComment *vorbis_comment, const QByteArray &data, const QString &mimetype) const; + void SetEmbeddedCover(TagLib::ID3v2::Tag *tag, const QByteArray &data, const QString &mimetype) const; + void SetEmbeddedCover(TagLib::MP4::File *aac_file, TagLib::MP4::Tag *tag, const QByteArray &data, const QString &mimetype) const; + + static TagLib::String TagLibStringListToSlashSeparatedString(const TagLib::StringList &taglib_string_list); + + private: + FileRefFactory *factory_; + + Q_DISABLE_COPY(TagReaderTagLib) +}; + +#endif // TAGREADERTAGLIB_H diff --git a/src/tagreader/tagreaderwritefilerequest.cpp b/src/tagreader/tagreaderwritefilerequest.cpp new file mode 100644 index 000000000..8788d8992 --- /dev/null +++ b/src/tagreader/tagreaderwritefilerequest.cpp @@ -0,0 +1,24 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include + +#include "tagreaderwritefilerequest.h" + +TagReaderWriteFileRequest::TagReaderWriteFileRequest(const QString &_filename) : TagReaderRequest(_filename) {} diff --git a/src/tagreader/tagreaderwritefilerequest.h b/src/tagreader/tagreaderwritefilerequest.h new file mode 100644 index 000000000..07260d7a0 --- /dev/null +++ b/src/tagreader/tagreaderwritefilerequest.h @@ -0,0 +1,46 @@ +/* + * Strawberry Music Player + * Copyright 2024, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef TAGREADERWRITEFILEREQUEST_H +#define TAGREADERWRITEFILEREQUEST_H + +#include + +#include "core/shared_ptr.h" +#include "core/song.h" +#include "tagreaderrequest.h" +#include "savetagsoptions.h" +#include "savetagcoverdata.h" + +using std::make_shared; + +class TagReaderWriteFileRequest : public TagReaderRequest { + public: + explicit TagReaderWriteFileRequest(const QString &_filename); + + static SharedPtr Create(const QString &filename) { return make_shared(filename); } + + SaveTagsOptions save_tags_options; + Song song; + SaveTagCoverData save_tag_cover_data; +}; + +using TagReaderWriteFileRequestPtr = SharedPtr; + +#endif // TAGREADERWRITEFILEREQUEST_H diff --git a/src/translations/translations.pot b/src/translations/translations.pot index 0ff05a39e..9560bfe63 100644 --- a/src/translations/translations.pot +++ b/src/translations/translations.pot @@ -394,10 +394,6 @@ msgstr "" msgid "Couldn't link GStreamer source, typefind and fakesink elements for %1" msgstr "" -#, qt-format -msgid "Failed to load image from data for %1" -msgstr "" - msgid "Playlist" msgstr "" @@ -444,6 +440,34 @@ msgid "" "them all?" msgstr "" +#, qt-format +msgid "Failed to load image from data for %1" +msgstr "" + +msgid "Success" +msgstr "" + +msgid "File is unsupported" +msgstr "" + +msgid "Filename is missing" +msgstr "" + +msgid "File does not exist" +msgstr "" + +msgid "File could not be opened" +msgstr "" + +msgid "Could not parse file" +msgstr "" + +msgid "Could save file" +msgstr "" + +msgid "Unknown error" +msgstr "" + msgid "" "Prefix a search term with a field name to limit the search to that field, e." "g.:" @@ -843,11 +867,11 @@ msgid "Sample rate" msgstr "" #, qt-format -msgid "Could not write metadata to %1: %2" +msgid "Could not write metadata to %1" msgstr "" #, qt-format -msgid "Could not write metadata to %1" +msgid "Could not write metadata to %1: %2" msgstr "" msgid "Title" @@ -2328,9 +2352,6 @@ msgstr "" msgid "Retrieving album covers for %1 albums..." msgstr "" -msgid "Unknown error" -msgstr "" - msgid "Configuration incomplete" msgstr "" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ee8ada564..db3d537d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,7 +21,6 @@ target_include_directories(test_utils SYSTEM PRIVATE target_include_directories(test_utils PRIVATE ${CMAKE_BINARY_DIR}/src ${CMAKE_SOURCE_DIR}/src - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common ) target_link_directories(test_utils PRIVATE ${SQLITE_LIBRARY_DIRS} @@ -41,15 +40,12 @@ add_custom_target(strawberry_tests echo "Running Strawberry tests" WORKING_DIREC add_custom_target(build_tests WORKING_DIRECTORY ${CURRENT_BINARY_DIR}) add_dependencies(strawberry_tests build_tests) -qt_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc) +qt_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc ${CMAKE_SOURCE_DIR}/data/data.qrc ${CMAKE_SOURCE_DIR}/data/icons.qrc) add_library(test_gui_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp) target_include_directories(test_gui_main PRIVATE ${CMAKE_BINARY_DIR}/src ${CMAKE_SOURCE_DIR}/src - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader ) if(HAVE_GSTREAMER) target_include_directories(test_gui_main SYSTEM PRIVATE ${GSTREAMER_INCLUDE_DIRS}) @@ -61,9 +57,6 @@ add_library(test_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main. target_include_directories(test_main PRIVATE ${CMAKE_BINARY_DIR}/src ${CMAKE_SOURCE_DIR}/src - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader ) if(HAVE_GSTREAMER) target_include_directories(test_main SYSTEM PRIVATE ${GSTREAMER_INCLUDE_DIRS}) @@ -81,9 +74,6 @@ macro(add_test_file test_source gui_required) target_include_directories(${TEST_NAME} PRIVATE ${CMAKE_BINARY_DIR}/src ${CMAKE_SOURCE_DIR}/src - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-common - ${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader - ${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader ${TAGLIB_INCLUDE_DIRS} ) target_link_libraries(${TEST_NAME} PRIVATE @@ -113,7 +103,7 @@ add_test_file(src/mergedproxymodel_test.cpp false) add_test_file(src/sqlite_test.cpp false) add_test_file(src/tagreader_test.cpp false) add_test_file(src/collectionbackend_test.cpp false) -add_test_file(src/collectionmodel_test.cpp false) +add_test_file(src/collectionmodel_test.cpp true) add_test_file(src/songplaylistitem_test.cpp false) add_test_file(src/organizeformat_test.cpp false) add_test_file(src/playlist_test.cpp true) diff --git a/tests/src/resources_env.h b/tests/src/resources_env.h index 9dacda81a..dc6b54b68 100644 --- a/tests/src/resources_env.h +++ b/tests/src/resources_env.h @@ -32,6 +32,7 @@ class ResourcesEnvironment : public ::testing::Environment { ResourcesEnvironment() = default; void SetUp() override { Q_INIT_RESOURCE(data); + Q_INIT_RESOURCE(icons); Q_INIT_RESOURCE(testdata); #ifdef HAVE_TRANSLATIONS Q_INIT_RESOURCE(translations); diff --git a/tests/src/tagreader_test.cpp b/tests/src/tagreader_test.cpp index 9582327d5..b4cf4a751 100644 --- a/tests/src/tagreader_test.cpp +++ b/tests/src/tagreader_test.cpp @@ -26,57 +26,56 @@ #include #include #include +#include +#include #include "core/song.h" - -#if defined(HAVE_TAGLIB) -# include "tagreadertaglib.h" -#elif defined(HAVE_TAGPARSER) -# include "tagreadertagparser.h" -#endif +#include "tagreader/tagreaderclient.h" #include "test_utils.h" +using std::make_shared; +using namespace Qt::StringLiterals; + // clazy:excludeall=non-pod-global-static namespace { class TagReaderTest : public ::testing::Test { protected: - static void SetUpTestCase() { - // Return something from uninteresting mock functions. -#if defined(HAVE_TAGLIB) - testing::DefaultValue::Set("foobarbaz"); -#endif + + void SetUp() override { + tagread_client_thread_ = new QThread(); + tagreader_client_ = make_shared(); + tagreader_client_->moveToThread(tagread_client_thread_); + tagread_client_thread_->start(); } - static Song ReadSongFromFile(const QString& filename) { -#if defined(HAVE_TAGLIB) - TagReaderTagLib tag_reader; -#elif defined(HAVE_TAGPARSER) - TagReaderTagParser tag_reader; -#endif - Song song; - ::spb::tagreader::SongMetadata pb_song; + static void SetUpTestCase() { + // Return something from uninteresting mock functions. + testing::DefaultValue::Set("foobarbaz"); + } + + static Song ReadSongFromFile(const QString &filename) { + + TagReaderReadFileReplyPtr reply = TagReaderClient::Instance()->ReadFileAsync(filename); + + QEventLoop loop; + QObject::connect(&*reply, &TagReaderReadFileReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + + return reply->song(); - // We need to init protobuf object from a Song object, to have default values initialized correctly. - song.ToProtobuf(&pb_song); - tag_reader.ReadFile(filename, &pb_song); - song.InitFromProtobuf(pb_song); - return song; } static void WriteSongToFile(const Song &song, const QString &filename) { -#if defined(HAVE_TAGLIB) - TagReaderTagLib tag_reader; -#elif defined(HAVE_TAGPARSER) - TagReaderTagParser tag_reader; -#endif - ::spb::tagreader::WriteFileRequest request; - request.set_filename(filename.toStdString()); - request.set_save_tags(true); - song.ToProtobuf(request.mutable_metadata()); - tag_reader.WriteFile(filename, request); + + TagReaderReplyPtr reply = TagReaderClient::Instance()->WriteFileAsync(filename, song, SaveTagsOption::Tags, SaveTagCoverData()); + + QEventLoop loop; + QObject::connect(&*reply, &TagReaderReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + } static QString SHA256SUM(const QString &filename) { @@ -97,32 +96,53 @@ class TagReaderTest : public ::testing::Test { } static void WriteSongPlaycountToFile(const Song &song, const QString &filename) { -#if defined(HAVE_TAGLIB) - TagReaderTagLib tag_reader; -#elif defined(HAVE_TAGPARSER) - TagReaderTagParser tag_reader; -#endif - spb::tagreader::SongMetadata pb_song; - song.ToProtobuf(&pb_song); - tag_reader.SaveSongPlaycountToFile(filename, pb_song.playcount()); + + TagReaderReplyPtr reply = TagReaderClient::Instance()->SaveSongPlaycountAsync(filename, song.playcount()); + QEventLoop loop; + QObject::connect(&*reply, &TagReaderReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + } static void WriteSongRatingToFile(const Song &song, const QString &filename) { -#if defined(HAVE_TAGLIB) - TagReaderTagLib tag_reader; -#elif defined(HAVE_TAGPARSER) - TagReaderTagParser tag_reader; -#endif - spb::tagreader::SongMetadata pb_song; - song.ToProtobuf(&pb_song); - tag_reader.SaveSongRatingToFile(filename, pb_song.rating()); + + TagReaderReplyPtr reply = TagReaderClient::Instance()->SaveSongRatingAsync(filename, song.rating()); + QEventLoop loop; + QObject::connect(&*reply, &TagReaderReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + } + static QImage ReadCoverFromFile(const QString &filename) { + + TagReaderLoadCoverImageReplyPtr reply = TagReaderClient::Instance()->LoadCoverImageAsync(filename); + QEventLoop loop; + QObject::connect(&*reply, &TagReaderLoadCoverImageReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + + return reply->image(); + + } + + static TagReaderResult WriteCoverToFile(const QString &filename, const SaveTagCoverData &save_tag_cover_data) { + + TagReaderReplyPtr reply = TagReaderClient::Instance()->SaveCoverAsync(filename, save_tag_cover_data); + QEventLoop loop; + QObject::connect(&*reply, &TagReaderReply::Finished, &loop, &QEventLoop::quit); + loop.exec(); + + return reply->result(); + + } + + QThread *tagread_client_thread_ = nullptr; + SharedPtr tagreader_client_; + }; TEST_F(TagReaderTest, TestFLACAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.flac")); + TemporaryResource r(u":/audio/strawberry.flac"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -131,7 +151,7 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.flac")); + QFile orig_file(u":/audio/strawberry.flac"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -156,16 +176,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -179,16 +199,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -197,16 +217,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -216,16 +236,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -234,16 +254,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -253,16 +273,16 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -287,7 +307,7 @@ TEST_F(TagReaderTest, TestFLACAudioFileTagging) { TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.wv")); + TemporaryResource r(u":/audio/strawberry.wv"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -296,7 +316,7 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.wv")); + QFile orig_file(u":/audio/strawberry.wv"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -321,16 +341,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -344,16 +364,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -362,16 +382,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -381,16 +401,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -399,16 +419,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -418,16 +438,16 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -452,7 +472,7 @@ TEST_F(TagReaderTest, TestWavPackAudioFileTagging) { TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.oga")); + TemporaryResource r(u":/audio/strawberry.oga"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -461,7 +481,7 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.oga")); + QFile orig_file(u":/audio/strawberry.oga"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -486,16 +506,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -509,16 +529,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -527,16 +547,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -546,16 +566,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -564,16 +584,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -583,16 +603,16 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -617,7 +637,7 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileTagging) { TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.ogg")); + TemporaryResource r(u":/audio/strawberry.ogg"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -626,7 +646,7 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.ogg")); + QFile orig_file(u":/audio/strawberry.ogg"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -651,16 +671,16 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -674,16 +694,16 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -692,16 +712,16 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -711,15 +731,15 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -728,16 +748,16 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -747,16 +767,16 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -781,7 +801,7 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileTagging) { TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.opus")); + TemporaryResource r(u":/audio/strawberry.opus"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -790,7 +810,7 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.opus")); + QFile orig_file(u":/audio/strawberry.opus"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -815,16 +835,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -838,16 +858,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -856,16 +876,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -875,16 +895,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -893,16 +913,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -912,16 +932,16 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -946,7 +966,7 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileTagging) { TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.spx")); + TemporaryResource r(u":/audio/strawberry.spx"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -955,7 +975,7 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.spx")); + QFile orig_file(u":/audio/strawberry.spx"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -980,16 +1000,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1003,16 +1023,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1021,16 +1041,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -1040,16 +1060,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -1058,16 +1078,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1077,16 +1097,16 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1111,7 +1131,7 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileTagging) { TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.aif")); + TemporaryResource r(u":/audio/strawberry.aif"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -1120,7 +1140,7 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.aif")); + QFile orig_file(u":/audio/strawberry.aif"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -1145,16 +1165,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1168,16 +1188,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - //EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - //EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - //EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + //EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + //EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + //EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + //EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); //EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1186,16 +1206,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -1205,16 +1225,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - //EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - //EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - //EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + //EXPECT_EQ(u"new album artist"_s, song.albumartist()); + //EXPECT_EQ(u"new composer"_s, song.composer()); + //EXPECT_EQ(u"new performer"_s, song.performer()); + //EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + //EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); //EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -1223,16 +1243,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1242,16 +1262,16 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - //EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - //EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - //EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + //EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + //EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + //EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + //EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); //EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1276,7 +1296,7 @@ TEST_F(TagReaderTest, TestAIFFAudioFileTagging) { TEST_F(TagReaderTest, TestASFAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.asf")); + TemporaryResource r(u":/audio/strawberry.asf"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -1285,7 +1305,7 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.asf")); + QFile orig_file(u":/audio/strawberry.asf"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -1310,16 +1330,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1333,16 +1353,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + //EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1352,16 +1372,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -1371,16 +1391,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + //EXPECT_EQ(u"new performer"_s, song.performer()); + //EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -1389,16 +1409,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1408,16 +1428,16 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - //EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + //EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1442,7 +1462,7 @@ TEST_F(TagReaderTest, TestASFAudioFileTagging) { TEST_F(TagReaderTest, TestMP3AudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.mp3")); + TemporaryResource r(u":/audio/strawberry.mp3"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -1451,7 +1471,7 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.mp3")); + QFile orig_file(u":/audio/strawberry.mp3"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -1476,16 +1496,16 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1499,16 +1519,16 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1517,16 +1537,16 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -1536,17 +1556,17 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); EXPECT_EQ(4321, song.disc()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(9102, song.year()); //EXPECT_EQ(9102, song.originalyear()); @@ -1554,16 +1574,16 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1573,16 +1593,16 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1607,7 +1627,7 @@ TEST_F(TagReaderTest, TestMP3AudioFileTagging) { TEST_F(TagReaderTest, TestM4AAudioFileTagging) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.m4a")); + TemporaryResource r(u":/audio/strawberry.m4a"_s); QString sha256sum_notags = SHA256SUM(r.fileName()); EXPECT_FALSE(sha256sum_notags.isEmpty()); @@ -1616,7 +1636,7 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { QByteArray orig_file_data; QByteArray temp_file_data; { - QFile orig_file(QStringLiteral(":/audio/strawberry.m4a")); + QFile orig_file(u":/audio/strawberry.m4a"_s); orig_file.open(QIODevice::ReadOnly); EXPECT_TRUE(orig_file.isOpen()); orig_file_data = orig_file.readAll(); @@ -1641,16 +1661,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Write tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1664,16 +1684,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Read tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1682,16 +1702,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Write new tags Song song; - song.set_title(QStringLiteral("new title")); - song.set_artist(QStringLiteral("new artist")); - song.set_album(QStringLiteral("new album")); - song.set_albumartist(QStringLiteral("new album artist")); - song.set_composer(QStringLiteral("new composer")); - song.set_performer(QStringLiteral("new performer")); - song.set_grouping(QStringLiteral("new grouping")); - song.set_genre(QStringLiteral("new genre")); - song.set_comment(QStringLiteral("new comment")); - song.set_lyrics(QStringLiteral("new lyrics")); + song.set_title(u"new title"_s); + song.set_artist(u"new artist"_s); + song.set_album(u"new album"_s); + song.set_albumartist(u"new album artist"_s); + song.set_composer(u"new composer"_s); + song.set_performer(u"new performer"_s); + song.set_grouping(u"new grouping"_s); + song.set_genre(u"new genre"_s); + song.set_comment(u"new comment"_s); + song.set_lyrics(u"new lyrics"_s); song.set_track(21); song.set_disc(4321); song.set_year(9102); @@ -1701,16 +1721,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Read new tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("new title"), song.title()); - EXPECT_EQ(QStringLiteral("new artist"), song.artist()); - EXPECT_EQ(QStringLiteral("new album"), song.album()); - EXPECT_EQ(QStringLiteral("new album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("new composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("new performer"), song.performer()); - EXPECT_EQ(QStringLiteral("new grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("new genre"), song.genre()); - EXPECT_EQ(QStringLiteral("new comment"), song.comment()); - EXPECT_EQ(QStringLiteral("new lyrics"), song.lyrics()); + EXPECT_EQ(u"new title"_s, song.title()); + EXPECT_EQ(u"new artist"_s, song.artist()); + EXPECT_EQ(u"new album"_s, song.album()); + EXPECT_EQ(u"new album artist"_s, song.albumartist()); + EXPECT_EQ(u"new composer"_s, song.composer()); + //EXPECT_EQ(u"new performer"_s, song.performer()); + EXPECT_EQ(u"new grouping"_s, song.grouping()); + EXPECT_EQ(u"new genre"_s, song.genre()); + EXPECT_EQ(u"new comment"_s, song.comment()); + EXPECT_EQ(u"new lyrics"_s, song.lyrics()); EXPECT_EQ(21, song.track()); EXPECT_EQ(4321, song.disc()); EXPECT_EQ(9102, song.year()); @@ -1719,16 +1739,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Write original tags Song song; - song.set_title(QStringLiteral("strawberry title")); - song.set_artist(QStringLiteral("strawberry artist")); - song.set_album(QStringLiteral("strawberry album")); - song.set_albumartist(QStringLiteral("strawberry album artist")); - song.set_composer(QStringLiteral("strawberry composer")); - song.set_performer(QStringLiteral("strawberry performer")); - song.set_grouping(QStringLiteral("strawberry grouping")); - song.set_genre(QStringLiteral("strawberry genre")); - song.set_comment(QStringLiteral("strawberry comment")); - song.set_lyrics(QStringLiteral("strawberry lyrics")); + song.set_title(u"strawberry title"_s); + song.set_artist(u"strawberry artist"_s); + song.set_album(u"strawberry album"_s); + song.set_albumartist(u"strawberry album artist"_s); + song.set_composer(u"strawberry composer"_s); + song.set_performer(u"strawberry performer"_s); + song.set_grouping(u"strawberry grouping"_s); + song.set_genre(u"strawberry genre"_s); + song.set_comment(u"strawberry comment"_s); + song.set_lyrics(u"strawberry lyrics"_s); song.set_track(12); song.set_disc(1234); song.set_year(2019); @@ -1738,16 +1758,16 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { { // Read original tags Song song = ReadSongFromFile(r.fileName()); - EXPECT_EQ(QStringLiteral("strawberry title"), song.title()); - EXPECT_EQ(QStringLiteral("strawberry artist"), song.artist()); - EXPECT_EQ(QStringLiteral("strawberry album"), song.album()); - EXPECT_EQ(QStringLiteral("strawberry album artist"), song.albumartist()); - EXPECT_EQ(QStringLiteral("strawberry composer"), song.composer()); - //EXPECT_EQ(QStringLiteral("strawberry performer"), song.performer()); - EXPECT_EQ(QStringLiteral("strawberry grouping"), song.grouping()); - EXPECT_EQ(QStringLiteral("strawberry genre"), song.genre()); - EXPECT_EQ(QStringLiteral("strawberry comment"), song.comment()); - EXPECT_EQ(QStringLiteral("strawberry lyrics"), song.lyrics()); + EXPECT_EQ(u"strawberry title"_s, song.title()); + EXPECT_EQ(u"strawberry artist"_s, song.artist()); + EXPECT_EQ(u"strawberry album"_s, song.album()); + EXPECT_EQ(u"strawberry album artist"_s, song.albumartist()); + EXPECT_EQ(u"strawberry composer"_s, song.composer()); + //EXPECT_EQ(u"strawberry performer"_s, song.performer()); + EXPECT_EQ(u"strawberry grouping"_s, song.grouping()); + EXPECT_EQ(u"strawberry genre"_s, song.genre()); + EXPECT_EQ(u"strawberry comment"_s, song.comment()); + EXPECT_EQ(u"strawberry lyrics"_s, song.lyrics()); EXPECT_EQ(12, song.track()); EXPECT_EQ(1234, song.disc()); EXPECT_EQ(2019, song.year()); @@ -1772,7 +1792,7 @@ TEST_F(TagReaderTest, TestM4AAudioFileTagging) { TEST_F(TagReaderTest, TestFLACAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.flac")); + TemporaryResource r(u":/audio/strawberry.flac"_s); { Song song; @@ -1800,7 +1820,7 @@ TEST_F(TagReaderTest, TestFLACAudioFileCompilation) { TEST_F(TagReaderTest, TestWavPackAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.wv")); + TemporaryResource r(u":/audio/strawberry.wv"_s); { Song song; @@ -1828,7 +1848,7 @@ TEST_F(TagReaderTest, TestWavPackAudioFileCompilation) { TEST_F(TagReaderTest, TestOggFLACAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.oga")); + TemporaryResource r(u":/audio/strawberry.oga"_s); { Song song; @@ -1856,7 +1876,7 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileCompilation) { TEST_F(TagReaderTest, TestOggVorbisAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.ogg")); + TemporaryResource r(u":/audio/strawberry.ogg"_s); { Song song; @@ -1884,7 +1904,7 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileCompilation) { TEST_F(TagReaderTest, TestOggOpusAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.opus")); + TemporaryResource r(u":/audio/strawberry.opus"_s); { Song song; @@ -1912,7 +1932,7 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileCompilation) { TEST_F(TagReaderTest, TestOggSpeexAudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.spx")); + TemporaryResource r(u":/audio/strawberry.spx"_s); { Song song; @@ -1940,7 +1960,7 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileCompilation) { TEST_F(TagReaderTest, TestMP3AudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.mp3")); + TemporaryResource r(u":/audio/strawberry.mp3"_s); { Song song; @@ -1968,7 +1988,7 @@ TEST_F(TagReaderTest, TestMP3AudioFileCompilation) { TEST_F(TagReaderTest, TestMP4AudioFileCompilation) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.m4a")); + TemporaryResource r(u":/audio/strawberry.m4a"_s); { Song song; @@ -1994,11 +2014,9 @@ TEST_F(TagReaderTest, TestMP4AudioFileCompilation) { } -#ifndef HAVE_TAGPARSER - TEST_F(TagReaderTest, TestFLACAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.flac")); + TemporaryResource r(u":/audio/strawberry.flac"_s); { Song song; @@ -2015,7 +2033,7 @@ TEST_F(TagReaderTest, TestFLACAudioFilePlaycount) { TEST_F(TagReaderTest, TestWavPackAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.wv")); + TemporaryResource r(u":/audio/strawberry.wv"_s); { Song song; @@ -2032,7 +2050,7 @@ TEST_F(TagReaderTest, TestWavPackAudioFilePlaycount) { TEST_F(TagReaderTest, TestOggFLACAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.oga")); + TemporaryResource r(u":/audio/strawberry.oga"_s); { Song song; @@ -2049,7 +2067,7 @@ TEST_F(TagReaderTest, TestOggFLACAudioFilePlaycount) { TEST_F(TagReaderTest, TestOggVorbisAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.ogg")); + TemporaryResource r(u":/audio/strawberry.ogg"_s); { Song song; @@ -2066,7 +2084,7 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFilePlaycount) { TEST_F(TagReaderTest, TestOggOpusAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.opus")); + TemporaryResource r(u":/audio/strawberry.opus"_s); { Song song; @@ -2083,7 +2101,7 @@ TEST_F(TagReaderTest, TestOggOpusAudioFilePlaycount) { TEST_F(TagReaderTest, TestOggSpeexAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.spx")); + TemporaryResource r(u":/audio/strawberry.spx"_s); { Song song; @@ -2100,7 +2118,7 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFilePlaycount) { TEST_F(TagReaderTest, TestOggASFAudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.asf")); + TemporaryResource r(u":/audio/strawberry.asf"_s); { Song song; @@ -2117,7 +2135,7 @@ TEST_F(TagReaderTest, TestOggASFAudioFilePlaycount) { TEST_F(TagReaderTest, TestMP3AudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.mp3")); + TemporaryResource r(u":/audio/strawberry.mp3"_s); { Song song; @@ -2134,7 +2152,7 @@ TEST_F(TagReaderTest, TestMP3AudioFilePlaycount) { TEST_F(TagReaderTest, TestMP4AudioFilePlaycount) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.m4a")); + TemporaryResource r(u":/audio/strawberry.m4a"_s); { Song song; @@ -2149,11 +2167,9 @@ TEST_F(TagReaderTest, TestMP4AudioFilePlaycount) { } -#endif // HAVE_TAGPARSER - TEST_F(TagReaderTest, TestFLACAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.flac")); + TemporaryResource r(u":/audio/strawberry.flac"_s); { Song song; @@ -2170,7 +2186,7 @@ TEST_F(TagReaderTest, TestFLACAudioFileRating) { TEST_F(TagReaderTest, TestWavPackAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.wv")); + TemporaryResource r(u":/audio/strawberry.wv"_s); { Song song; @@ -2187,7 +2203,7 @@ TEST_F(TagReaderTest, TestWavPackAudioFileRating) { TEST_F(TagReaderTest, TestOggFLACAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.oga")); + TemporaryResource r(u":/audio/strawberry.oga"_s); { Song song; @@ -2204,7 +2220,7 @@ TEST_F(TagReaderTest, TestOggFLACAudioFileRating) { TEST_F(TagReaderTest, TestOggVorbisAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.ogg")); + TemporaryResource r(u":/audio/strawberry.ogg"_s); { Song song; @@ -2221,7 +2237,7 @@ TEST_F(TagReaderTest, TestOggVorbisAudioFileRating) { TEST_F(TagReaderTest, TestOggOpusAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.opus")); + TemporaryResource r(u":/audio/strawberry.opus"_s); { Song song; @@ -2238,7 +2254,7 @@ TEST_F(TagReaderTest, TestOggOpusAudioFileRating) { TEST_F(TagReaderTest, TestOggSpeexAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.spx")); + TemporaryResource r(u":/audio/strawberry.spx"_s); { Song song; @@ -2255,7 +2271,7 @@ TEST_F(TagReaderTest, TestOggSpeexAudioFileRating) { TEST_F(TagReaderTest, TestASFAudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.asf")); + TemporaryResource r(u":/audio/strawberry.asf"_s); { Song song; @@ -2272,7 +2288,7 @@ TEST_F(TagReaderTest, TestASFAudioFileRating) { TEST_F(TagReaderTest, TestMP3AudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.mp3")); + TemporaryResource r(u":/audio/strawberry.mp3"_s); { Song song; @@ -2289,7 +2305,7 @@ TEST_F(TagReaderTest, TestMP3AudioFileRating) { TEST_F(TagReaderTest, TestMP4AudioFileRating) { - TemporaryResource r(QStringLiteral(":/audio/strawberry.m4a")); + TemporaryResource r(u":/audio/strawberry.m4a"_s); { Song song; @@ -2304,4 +2320,106 @@ TEST_F(TagReaderTest, TestMP4AudioFileRating) { } +TEST_F(TagReaderTest, TestFLACAudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.flac"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + +TEST_F(TagReaderTest, TestOggVorbisAudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.ogg"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + +TEST_F(TagReaderTest, TestOggOpusAudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.opus"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + +TEST_F(TagReaderTest, TestOggSpeexAudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.spx"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + +TEST_F(TagReaderTest, TestMP3AudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.mp3"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + +TEST_F(TagReaderTest, TestMP4AudioFileCover) { + + TemporaryResource r(u":/audio/strawberry.mp4"_s); + const QString cover_filename = u":/pictures/strawberry.png"_s; + + QImage original_image; + EXPECT_TRUE(original_image.load(cover_filename)); + + TagReaderResult result = WriteCoverToFile(r.fileName(), cover_filename); + EXPECT_TRUE(result.success()); + + const QImage new_image = ReadCoverFromFile(r.fileName()); + EXPECT_TRUE(!new_image.isNull()); + EXPECT_EQ(new_image, original_image); + +} + } // namespace