Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ebf7cd273 | ||
|
|
9986088dc4 | ||
|
|
bfe0b2c634 | ||
|
|
cd2af6974c | ||
|
|
c452486573 | ||
|
|
79406b20f2 | ||
|
|
1226bc214d | ||
|
|
7da79dabdf | ||
|
|
b51026a2ee | ||
|
|
67d01f48a3 | ||
|
|
9fd5c5fc1c | ||
|
|
70bc5b83fa | ||
|
|
b380db51fa | ||
|
|
fab598ebff | ||
|
|
6f6d087fa2 | ||
|
|
6e463d1de3 | ||
|
|
21970f3065 | ||
|
|
9d7e44be2d | ||
|
|
9085fb8285 | ||
|
|
dd79d089f6 | ||
|
|
7aaad124d0 | ||
|
|
0025cb9f53 | ||
|
|
15c8f2a3ee | ||
|
|
fc1a2dac90 | ||
|
|
f698b860f7 | ||
|
|
86b057a301 | ||
|
|
b066158a4b | ||
|
|
046c822604 | ||
|
|
d427733bfc | ||
|
|
04d34a06c7 | ||
|
|
69d86513ae | ||
|
|
019b49a219 | ||
|
|
d9e787784a | ||
|
|
71969b88e3 | ||
|
|
7ae0f5e246 | ||
|
|
1ea7da4bb5 | ||
|
|
8b96bb5f27 | ||
|
|
aefce3ccd0 | ||
|
|
4e599e2aba | ||
|
|
4148c289af | ||
|
|
d575ab0b2b | ||
|
|
d09af19d3f | ||
|
|
a2dff17db9 | ||
|
|
c0fecb935f | ||
|
|
28249b7e99 | ||
|
|
eb63e2257f | ||
|
|
2211716d04 | ||
|
|
242137a50c | ||
|
|
c41311bf76 | ||
|
|
e0d959e3c5 | ||
|
|
f0a5c4b2c2 | ||
|
|
e10a50fdc1 | ||
|
|
380f2509ac | ||
|
|
c0fb35f6b9 | ||
|
|
3e658845d2 | ||
|
|
384209ba70 | ||
|
|
835b589894 | ||
|
|
76e684ee75 | ||
|
|
d0d2c83768 | ||
|
|
b476bc3168 | ||
|
|
5a2ad145e8 | ||
|
|
27233d2549 | ||
|
|
1a0bc75629 | ||
|
|
dc04961699 | ||
|
|
e594cf299e | ||
|
|
096c995a91 | ||
|
|
f64b175cd8 | ||
|
|
954e0e8a59 | ||
|
|
034b032cfa | ||
|
|
e33590bff9 | ||
|
|
55f610f3b2 | ||
|
|
87fd93a1cf | ||
|
|
2db77a248a | ||
|
|
f600274592 | ||
|
|
bc37d00a81 | ||
|
|
1956ea95ee | ||
|
|
a56e3b91e1 | ||
|
|
6bcc9d61e1 | ||
|
|
3ef34191a3 | ||
|
|
60de36aff9 | ||
|
|
b019dd1c51 | ||
|
|
3a083d5527 | ||
|
|
8006241a81 | ||
|
|
b05e3d24ee | ||
|
|
b78c0a4979 | ||
|
|
d3b3c309fa | ||
|
|
65615495d9 | ||
|
|
35f448c34f | ||
|
|
e1abd28a88 | ||
|
|
a109d8be64 | ||
|
|
333a0bc05a | ||
|
|
a831519b54 | ||
|
|
a25052ed96 | ||
|
|
676f8dc8be | ||
|
|
9c3cb82fca | ||
|
|
9b827f58ad | ||
|
|
22e327d391 | ||
|
|
451de4d72d | ||
|
|
0679b78c1d | ||
|
|
ad7084b897 | ||
|
|
3c068eaba9 | ||
|
|
819ae08c6a | ||
|
|
38414ad8de | ||
|
|
f0422f7634 | ||
|
|
2a004dadf3 | ||
|
|
b7ea586e44 | ||
|
|
2a5f286d07 | ||
|
|
0bc14671ec |
155
.gitignore
vendored
@@ -1,80 +1,117 @@
|
|||||||
# This file is used to ignore files which are generated
|
# This file is used to ignore files which are generated
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
*~
|
# Build
|
||||||
*.autosave
|
build/
|
||||||
*.a
|
bin/
|
||||||
*.core
|
|
||||||
*.moc
|
# CMake
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Makefile*
|
||||||
|
Testing
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
*.obj
|
||||||
*.orig
|
|
||||||
*.rej
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*_pch.h.cpp
|
*.dylib
|
||||||
*_resource.rc
|
*.dll
|
||||||
*.qm
|
|
||||||
.#*
|
# Fortran module files
|
||||||
*.*#
|
*.mod
|
||||||
core
|
*.smod
|
||||||
!core/
|
|
||||||
tags
|
# Compiled Static libraries
|
||||||
.DS_Store
|
*.lai
|
||||||
.directory
|
*.la
|
||||||
*.debug
|
*.a
|
||||||
Makefile*
|
*.lib
|
||||||
*.prl
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
# Dump files
|
||||||
|
*.core
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Qt
|
||||||
|
*build-*
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
ui_*.h
|
moc_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
Thumbs.db
|
ui_*.h
|
||||||
*.res
|
*.moc
|
||||||
*.rc
|
*.qm
|
||||||
/.qmake.cache
|
|
||||||
/.qmake.stash
|
|
||||||
*.spec
|
|
||||||
*.nsi
|
|
||||||
*.plist
|
|
||||||
maketarball.sh
|
|
||||||
dist/macos/create-dmg.sh
|
|
||||||
dist/debian/changelog
|
|
||||||
dist/pacman/PKGBUILD
|
|
||||||
|
|
||||||
# qtcreator generated files
|
# QtCreator
|
||||||
*.pro.user*
|
CMakeLists.txt.user*
|
||||||
|
*.pro.user
|
||||||
|
*.pro.user.*
|
||||||
|
*creator.user*
|
||||||
|
target_wrapper.*
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
# xemacs temporary files
|
# Temporary files
|
||||||
|
*~
|
||||||
|
*.autosave
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
.*.kate-swp
|
||||||
|
.swp.*
|
||||||
|
.*.swp
|
||||||
*.flc
|
*.flc
|
||||||
|
|
||||||
# Vim temporary files
|
# Directory files
|
||||||
.*.swp
|
.directory
|
||||||
|
.DS_Store
|
||||||
# Visual Studio generated files
|
Thumbs.db
|
||||||
*.ib_pdb_index
|
|
||||||
*.idb
|
|
||||||
*.ilk
|
|
||||||
*.pdb
|
|
||||||
*.sln
|
|
||||||
*.suo
|
|
||||||
*.vcproj
|
|
||||||
*vcproj.*.*.user
|
|
||||||
*.ncb
|
|
||||||
*.sdf
|
|
||||||
*.opensdf
|
|
||||||
*.vcxproj
|
|
||||||
*vcxproj.*
|
|
||||||
|
|
||||||
# MinGW generated files
|
# MinGW generated files
|
||||||
*.Debug
|
*.Debug
|
||||||
*.Release
|
*.Release
|
||||||
|
|
||||||
# Python byte code
|
# Package files
|
||||||
*.pyc
|
*.spec
|
||||||
|
*.nsi
|
||||||
|
*.plist
|
||||||
|
|
||||||
# Binaries
|
# Stuff in dist
|
||||||
# --------
|
maketarball.sh
|
||||||
*.dll
|
create-dmg.sh
|
||||||
*.exe
|
changelog
|
||||||
|
PKGBUILD
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
translations.pot
|
||||||
|
zanata.xml
|
||||||
|
.zanata-cache/
|
||||||
|
|
||||||
|
# Snap
|
||||||
|
parts/
|
||||||
|
prime/
|
||||||
|
stage/
|
||||||
|
*.snap
|
||||||
|
/snap/.snapcraft/
|
||||||
|
/*_source.tar.bz2
|
||||||
|
|||||||
12
.travis.yml
@@ -2,7 +2,7 @@ sudo: required
|
|||||||
language: C++
|
language: C++
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
#- osx
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
compiler:
|
compiler:
|
||||||
@@ -22,7 +22,7 @@ before_install:
|
|||||||
git pull;
|
git pull;
|
||||||
brew update;
|
brew update;
|
||||||
brew unlink python;
|
brew unlink python;
|
||||||
brew install glib pkgconfig protobuf protobuf-c qt;
|
brew install glib pkgconfig libffi protobuf protobuf-c qt gettext;
|
||||||
brew install sqlite --with-fts;
|
brew install sqlite --with-fts;
|
||||||
brew install gstreamer gst-plugins-base;
|
brew install gstreamer gst-plugins-base;
|
||||||
brew install gst-plugins-good --with-flac;
|
brew install gst-plugins-good --with-flac;
|
||||||
@@ -30,18 +30,20 @@ before_install:
|
|||||||
brew install chromaprint;
|
brew install chromaprint;
|
||||||
brew install libcdio libmtp libimobiledevice libplist;
|
brew install libcdio libmtp libimobiledevice libplist;
|
||||||
export Qt5_DIR=/usr/local/opt/qt5/lib/cmake;
|
export Qt5_DIR=/usr/local/opt/qt5/lib/cmake;
|
||||||
|
export Qt5LinguistTools_DIR=/usr/local/Cellar/qt/$(ls /usr/local/Cellar/qt | head -n1)/lib/cmake/Qt5LinguistTools;
|
||||||
|
export PATH="/usr/local/opt/gettext/bin:$PATH";
|
||||||
ls /usr/local/lib/gstreamer-1.0;
|
ls /usr/local/lib/gstreamer-1.0;
|
||||||
fi
|
fi
|
||||||
before_script:
|
before_script:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild -DENABLE_STREAM_DEEZER=ON ; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild -DENABLE_TRANSLATIONS=ON ; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON -DENABLE_STREAM_DEEZER=ON ; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON -DENABLE_TRANSLATIONS=ON ; fi
|
||||||
script:
|
script:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||||
make -j8;
|
make -j8;
|
||||||
sudo make install;
|
sudo make install;
|
||||||
sudo ../dist/macos/macdeploy.py strawberry.app;
|
sudo ../dist/macos/macdeploy.py strawberry.app;
|
||||||
../dist/macos/create-dmg.sh strawberry.app;
|
../dist/macos/create-dmg.sh strawberry.app $CC_FOR_BUILD;
|
||||||
fi
|
fi
|
||||||
after_success:
|
after_success:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ls -lh strawberry.dmg; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ls -lh strawberry.dmg; fi
|
||||||
|
|||||||
38
3rdparty/README.md
vendored
@@ -7,28 +7,11 @@ This is a small static library used by Strawberry to prevent it from starting tw
|
|||||||
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
||||||
If you dynamically link to your systems version, you'll need two versions, one defined as QApplication and
|
If you dynamically link to your systems version, you'll need two versions, one defined as QApplication and
|
||||||
one as a QCoreApplication.
|
one as a QCoreApplication.
|
||||||
It is included here because it is normally not packaged by distros, and is also used on macOS and Windows.
|
It is included here because it is not packed by distros and is also used on macOS and Windows.
|
||||||
|
|
||||||
URL: https://github.com/itay-grudev/SingleApplication
|
URL: https://github.com/itay-grudev/SingleApplication
|
||||||
|
|
||||||
|
|
||||||
qocoa
|
|
||||||
-----
|
|
||||||
This is a small static library currently used for the search fields above the collection, playlist and in
|
|
||||||
the cover manager. It is slightly modified from original version, so it should not be used as a dynamic
|
|
||||||
library.
|
|
||||||
The plan in the long run is to replace it with something else.
|
|
||||||
|
|
||||||
URL: https://github.com/mikemcquaid/Qocoa
|
|
||||||
|
|
||||||
|
|
||||||
SPMediaKeyTap
|
|
||||||
-------------
|
|
||||||
|
|
||||||
This is used for macOS only to enable strawberry to grab global shortcuts and can safely be deleted on other
|
|
||||||
platforms.
|
|
||||||
|
|
||||||
|
|
||||||
taglib
|
taglib
|
||||||
------
|
------
|
||||||
|
|
||||||
@@ -38,9 +21,9 @@ correctly.
|
|||||||
|
|
||||||
It is kept in 3rdparty because there currently is no offical release of TagLib with the features and bugfixes
|
It is kept in 3rdparty because there currently is no offical release of TagLib with the features and bugfixes
|
||||||
that are in the official repository. And also because some distros use older, or unpatched versions.
|
that are in the official repository. And also because some distros use older, or unpatched versions.
|
||||||
This version is a unmodified copy of commit 5cb589a (sha: 5cb589a5b82c13ba8f0542e5e79629da7645cb3c).
|
|
||||||
|
|
||||||
Also, there is a bug in version 1.11.1 corrupting Ogg files, see: https://github.com/taglib/taglib/issues/864
|
There is a bug in the latest version (1.11.1) corrupting Ogg files,
|
||||||
|
see: https://github.com/taglib/taglib/issues/864
|
||||||
If you decide to use the systems taglib, make sure it has been patched with the following commit:
|
If you decide to use the systems taglib, make sure it has been patched with the following commit:
|
||||||
https://github.com/taglib/taglib/commit/9336c82da3a04552168f208cd7a5fa4646701ea4
|
https://github.com/taglib/taglib/commit/9336c82da3a04552168f208cd7a5fa4646701ea4
|
||||||
|
|
||||||
@@ -57,3 +40,18 @@ utf8-cpp
|
|||||||
This is 2 header files used by taglib, but kept in a seperate directory because it is maintained by others.
|
This is 2 header files used by taglib, but kept in a seperate directory because it is maintained by others.
|
||||||
|
|
||||||
URL: http://utfcpp.sourceforge.net/
|
URL: http://utfcpp.sourceforge.net/
|
||||||
|
|
||||||
|
|
||||||
|
qocoa
|
||||||
|
-----
|
||||||
|
This is a small static library currently used for the search fields above the collection, playlist and in
|
||||||
|
the cover manager. It is slightly modified from original version.
|
||||||
|
|
||||||
|
URL: https://github.com/mikemcquaid/Qocoa
|
||||||
|
|
||||||
|
|
||||||
|
SPMediaKeyTap
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This is used for macOS only to enable strawberry to grab global shortcuts and can safely be deleted on other
|
||||||
|
platforms.
|
||||||
|
|||||||
6
3rdparty/taglib/mp4/mp4properties.cpp
vendored
@@ -175,11 +175,11 @@ MP4::Properties::read(File *file, Atoms *atoms)
|
|||||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unit = data.toLongLong(28U);
|
unit = data.toUInt(28U);
|
||||||
length = data.toLongLong(36U);
|
length = data.toLongLong(32U);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(data.size() < 24 + 4) {
|
if(data.size() < 24 + 8) {
|
||||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,8 +112,7 @@ pkg_check_modules(LIBMTP libmtp>=1.0)
|
|||||||
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
|
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
|
||||||
pkg_check_modules(LIBUSBMUXD libusbmuxd)
|
pkg_check_modules(LIBUSBMUXD libusbmuxd)
|
||||||
pkg_check_modules(LIBPLIST libplist)
|
pkg_check_modules(LIBPLIST libplist)
|
||||||
pkg_check_modules(LIBDEEZER libdeezer)
|
find_package(Gettext)
|
||||||
pkg_check_modules(LIBDZMEDIA libdzmedia)
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
@@ -151,6 +150,11 @@ if(WIN32)
|
|||||||
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras)
|
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(Qt5LinguistTools CONFIG)
|
||||||
|
if (Qt5LinguistTools_FOUND)
|
||||||
|
set(QT_LCONVERT_EXECUTABLE Qt5::lconvert)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(X11_FOUND)
|
if(X11_FOUND)
|
||||||
find_path(KEYSYMDEF_H NAMES "keysymdef.h" PATHS "${X11_INCLUDE_DIR}" PATH_SUFFIXES "X11")
|
find_path(KEYSYMDEF_H NAMES "keysymdef.h" PATHS "${X11_INCLUDE_DIR}" PATH_SUFFIXES "X11")
|
||||||
find_path(XF86KEYSYM_H NAMES "XF86keysym.h" PATHS "${XCB_INCLUDEDIR}" PATH_SUFFIXES "X11")
|
find_path(XF86KEYSYM_H NAMES "XF86keysym.h" PATHS "${XCB_INCLUDEDIR}" PATH_SUFFIXES "X11")
|
||||||
@@ -285,18 +289,6 @@ optional_component(PHONON OFF "Engine: Phonon backend (UNSTABLE)"
|
|||||||
DEPENDS "phonon4qt5" PHONON_FOUND
|
DEPENDS "phonon4qt5" PHONON_FOUND
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
optional_component(DEEZER ON "Engine: Deezer backend"
|
|
||||||
DEPENDS "libdeezer" LIBDEEZER_FOUND
|
|
||||||
)
|
|
||||||
else ()
|
|
||||||
optional_component(DEEZER ON "Engine: Deezer backend"
|
|
||||||
DEPENDS "Linux" LINUX
|
|
||||||
DEPENDS "libdeezer" LIBDEEZER_FOUND
|
|
||||||
DEPENDS "libpulse" LIBPULSE_FOUND
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
optional_component(CHROMAPRINT ON "Chromaprint (Tag fetching from Musicbrainz)"
|
optional_component(CHROMAPRINT ON "Chromaprint (Tag fetching from Musicbrainz)"
|
||||||
DEPENDS "chromaprint" CHROMAPRINT_FOUND
|
DEPENDS "chromaprint" CHROMAPRINT_FOUND
|
||||||
)
|
)
|
||||||
@@ -346,22 +338,12 @@ optional_component(SPARKLE ON "Sparkle integration"
|
|||||||
DEPENDS "Sparkle" SPARKLE
|
DEPENDS "Sparkle" SPARKLE
|
||||||
)
|
)
|
||||||
|
|
||||||
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
|
optional_component(TRANSLATIONS ON "Translations"
|
||||||
|
DEPENDS "gettext" GETTEXT_FOUND
|
||||||
if (LIBDZMEDIA_FOUND OR LIBDEEZER_FOUND)
|
DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND
|
||||||
optional_component(STREAM_DEEZER ON "Streaming: Deezer support")
|
|
||||||
else()
|
|
||||||
optional_component(STREAM_DEEZER OFF "Streaming: Deezer support")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
optional_component(DZMEDIA ON "DZMedia"
|
|
||||||
DEPENDS "libdzmedia" LIBDZMEDIA_FOUND
|
|
||||||
DEPENDS "Deezer support" HAVE_STREAM_DEEZER
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (HAVE_STREAM_DEEZER AND NOT HAVE_DZMEDIA AND NOT HAVE_DEEZER)
|
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
|
||||||
message(STATUS "Deezer is enabled, but not DZMedia or Deezer engine, only preview streams will be available.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
option(USE_BUNDLE "Bundle macOS dependencies" OFF)
|
option(USE_BUNDLE "Bundle macOS dependencies" OFF)
|
||||||
@@ -407,8 +389,8 @@ add_custom_target(uninstall
|
|||||||
|
|
||||||
# Show a summary of what we have enabled
|
# Show a summary of what we have enabled
|
||||||
summary_show()
|
summary_show()
|
||||||
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON AND NOT HAVE_DEEZER)
|
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON)
|
||||||
message(FATAL_ERROR "You need to have either GStreamer, Xine, VLC, Phonon or Deezer to compile!")
|
message(FATAL_ERROR "You need to have either GStreamer, Xine, VLC or Phonon to compile!")
|
||||||
elseif(NOT HAVE_GSTREAMER)
|
elseif(NOT HAVE_GSTREAMER)
|
||||||
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
40
Changelog
@@ -2,6 +2,46 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 0.5.3:
|
||||||
|
|
||||||
|
* Changed default tagging to albumartist in organise dialog
|
||||||
|
* Removed support for older taglib in tagreader
|
||||||
|
* Made lyrics selectable in context
|
||||||
|
* Added boom and rainbow analyzers
|
||||||
|
* Made it possible to use enter in shortcuts
|
||||||
|
* Replaced "no album cover" image
|
||||||
|
* Capitalized Strawberry in OSD and tooltip
|
||||||
|
* Added artist search to Tidal
|
||||||
|
* Created systray tooltip workaround for KDE
|
||||||
|
* Changed defaults for backend fade setting
|
||||||
|
* Changed backend settings to allow setting device back to automatic when a custom device is active
|
||||||
|
* Hide ALSA options on non-ALSA systems
|
||||||
|
* Showing errors in dialog when editing tags fails
|
||||||
|
* Update database immediately when saving tags were successful
|
||||||
|
* Show Strawberry icon in OSD when stopping track
|
||||||
|
* Added support for translations
|
||||||
|
* Renamed desktop and appdata files to follow freedesktop specifications
|
||||||
|
* No longer allowing X11 shortcuts on Wayland
|
||||||
|
* Fixed handling of UNC paths in gstreamer engine
|
||||||
|
* Added option to disable volume control
|
||||||
|
* Removed Deezer support (SDK discontinued and streams are encrypted)
|
||||||
|
* Added Norwegian and Spanish translations
|
||||||
|
* Added setting to allow automatically saving album covers directly to album directory
|
||||||
|
* Updated mimetypes
|
||||||
|
* Added basic support for system and custom icons
|
||||||
|
* Moved loading of device icons to device model
|
||||||
|
* Added better support for APE tags
|
||||||
|
* Fixed problems identifying song as collection songs when loading playlist files
|
||||||
|
* Fixed problems loading Tidal URLs from playlist files
|
||||||
|
* Added support for saving and restoring geometry in settings, organise and transcoder dialogs
|
||||||
|
* Improved Tidal error handling and automatic login
|
||||||
|
* Improved Tidal search to handle duplicate albums
|
||||||
|
* Notify collection backend about renamed files when organising files
|
||||||
|
* Added more background image options
|
||||||
|
* Removed API Seeds lyrics provider (require payment)
|
||||||
|
* Added group by format
|
||||||
|
* Fixed gstreamer leaks
|
||||||
|
|
||||||
Version 0.5.2:
|
Version 0.5.2:
|
||||||
|
|
||||||
* Added error handling and message for URL handler
|
* Added error handling and message for URL handler
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
from opensuse:tumbleweed
|
from opensuse/leap
|
||||||
|
|
||||||
run zypper --non-interactive --gpg-auto-import-keys ref
|
run zypper --non-interactive --gpg-auto-import-keys ref
|
||||||
run zypper --non-interactive --gpg-auto-import-keys dup -l -y
|
run zypper --non-interactive --gpg-auto-import-keys dup -l -y
|
||||||
|
|
||||||
run zypper --non-interactive --gpg-auto-import-keys install \
|
run zypper --non-interactive --gpg-auto-import-keys install \
|
||||||
lsb-release git tar make cmake gcc gcc-c++ pkg-config \
|
lsb-release git tar make cmake gcc gcc-c++ pkg-config gettext-tools \
|
||||||
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
|
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
|
||||||
boost-devel protobuf-devel sqlite3-devel taglib-devel \
|
boost-devel protobuf-devel sqlite3-devel taglib-devel \
|
||||||
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-devel \
|
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-devel \
|
||||||
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5Sql-devel \
|
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5Sql-devel \
|
||||||
libQt5DBus-devel libqt5-qtx11extras-devel libqt5-qtbase-common-devel \
|
libQt5DBus-devel libqt5-qtx11extras-devel libqt5-qtbase-common-devel libqt5-linguist-devel \
|
||||||
libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel
|
libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel
|
||||||
|
|
||||||
run mkdir -p /usr/src/app
|
run mkdir -p /usr/src/app
|
||||||
|
|||||||
14
README.md
@@ -2,7 +2,7 @@
|
|||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8)
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8)
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
Strawberry is a audio player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles. The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.
|
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles. The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.
|
||||||
|
|
||||||
* Website: https://www.strawbs.org/
|
* Website: https://www.strawbs.org/
|
||||||
* Github: https://github.com/jonaski/strawberry
|
* Github: https://github.com/jonaski/strawberry
|
||||||
@@ -20,12 +20,12 @@ Strawberry is a audio player and music collection organizer. It is a fork of Cle
|
|||||||
* Edit tags on music files
|
* Edit tags on music files
|
||||||
* Fetch tags from MusicBrainz
|
* Fetch tags from MusicBrainz
|
||||||
* Album cover art from Last.fm, Musicbrainz and Discogs
|
* Album cover art from Last.fm, Musicbrainz and Discogs
|
||||||
* Song lyrics from AudD and API Seeds
|
* Song lyrics from AudD
|
||||||
* Support for multiple backends
|
* Support for multiple backends
|
||||||
* Audio analyzer
|
* Audio analyzer
|
||||||
* Audio equalizer
|
* Audio equalizer
|
||||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||||
* Streaming support for Tidal and Deezer
|
* Streaming support for Tidal
|
||||||
* Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
* Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
||||||
|
|
||||||
It has so far been tested to work on Linux, OpenBSD, macOS and Windows.
|
It has so far been tested to work on Linux, OpenBSD, macOS and Windows.
|
||||||
@@ -48,7 +48,7 @@ To build Strawberry from source you need the following installed on your system
|
|||||||
* [ALSA library (linux)](https://www.alsa-project.org/)
|
* [ALSA library (linux)](https://www.alsa-project.org/)
|
||||||
* [DBus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
|
* [DBus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
|
||||||
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
|
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
|
||||||
* [GStreamer](https://gstreamer.freedesktop.org/), [Xine](https://www.xine-project.org), [VLC](https://www.videolan.org), [Deezer](https://build-repo.deezer.com/native_sdk/deezer-native-sdk-v1.2.10.zip) or [Phonon](https://techbase.kde.org/Phonon)
|
* [GStreamer](https://gstreamer.freedesktop.org/), [Xine](https://www.xine-project.org), [VLC](https://www.videolan.org) or [Phonon](https://techbase.kde.org/Phonon)
|
||||||
|
|
||||||
Optional dependencies:
|
Optional dependencies:
|
||||||
|
|
||||||
@@ -57,13 +57,9 @@ Optional dependencies:
|
|||||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||||
* iPhone, iPod Touch, iPad and Apple TV devices: [libimobiledevice, libplist and libusbmuxd](https://www.libimobiledevice.org/)
|
* iPhone, iPod Touch, iPad and Apple TV devices: [libimobiledevice, libplist and libusbmuxd](https://www.libimobiledevice.org/)
|
||||||
|
|
||||||
Either GStreamer, Xine, VLC, Deezer or Phonon engine is required, but only GStreamer is fully implemented so far.
|
Either GStreamer, Xine, VLC or Phonon engine is required, but only GStreamer is fully implemented so far.
|
||||||
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
|
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
|
||||||
|
|
||||||
Deezer streams with full songs are encrypted and only urls for preview streams (MP3) are exposed by the API.
|
|
||||||
Full length songs requires the use of deezers own engine (Deezer SDK).
|
|
||||||
The Deezer SDK can be found here: https://build-repo.deezer.com/native_sdk/deezer-native-sdk-v1.2.10.zip
|
|
||||||
|
|
||||||
### :wrench: Compiling from source
|
### :wrench: Compiling from source
|
||||||
|
|
||||||
### Get the code:
|
### Get the code:
|
||||||
|
|||||||
77
cmake/Translations.cmake
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
|
||||||
|
find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
|
||||||
|
if(NOT GETTEXT_XGETTEXT_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "Could not find xgettext executable")
|
||||||
|
endif(NOT GETTEXT_XGETTEXT_EXECUTABLE)
|
||||||
|
|
||||||
|
set (XGETTEXT_OPTIONS
|
||||||
|
--qt
|
||||||
|
--keyword=tr:1,2c
|
||||||
|
--keyword=tr --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
|
||||||
|
--keyword=trUtf8 --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
|
||||||
|
--keyword=translate:2,3c
|
||||||
|
--keyword=translate:2 --flag=translate:2:pass-c-format --flag=translate:2:pass-qt-format
|
||||||
|
--keyword=QT_TR_NOOP --flag=QT_TR_NOOP:1:pass-c-format --flag=QT_TR_NOOP:1:pass-qt-format
|
||||||
|
--keyword=QT_TRANSLATE_NOOP:2 --flag=QT_TRANSLATE_NOOP:2:pass-c-format --flag=QT_TRANSLATE_NOOP:2:pass-qt-format
|
||||||
|
--keyword=_ --flag=_:1:pass-c-format --flag=_:1:pass-qt-format
|
||||||
|
--keyword=N_ --flag=N_:1:pass-c-format --flag=N_:1:pass-qt-format
|
||||||
|
--from-code=utf-8
|
||||||
|
)
|
||||||
|
|
||||||
|
macro(add_pot outfiles header pot)
|
||||||
|
# Make relative filenames for all source files
|
||||||
|
set(add_pot_sources)
|
||||||
|
foreach(_filename ${ARGN})
|
||||||
|
get_filename_component(_absolute_filename ${_filename} ABSOLUTE)
|
||||||
|
file(RELATIVE_PATH _relative_filename ${CMAKE_CURRENT_SOURCE_DIR} ${_absolute_filename})
|
||||||
|
list(APPEND add_pot_sources ${_relative_filename})
|
||||||
|
endforeach(_filename)
|
||||||
|
|
||||||
|
# Generate the .pot
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${pot}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -s -C --omit-header --output=${CMAKE_CURRENT_BINARY_DIR}/pot.temp ${add_pot_sources}
|
||||||
|
COMMAND cat ${header} ${CMAKE_CURRENT_BINARY_DIR}/pot.temp > ${pot}
|
||||||
|
DEPENDS ${add_pot_sources} ${header}
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND ${outfiles} ${pot})
|
||||||
|
endmacro(add_pot)
|
||||||
|
|
||||||
|
# Syntax is:
|
||||||
|
# add_po(sources_var po_prefix LANGUAGES language1 language2 ... DIRECTORY dir)
|
||||||
|
|
||||||
|
macro(add_po outfiles po_prefix)
|
||||||
|
parse_arguments(ADD_PO
|
||||||
|
"LANGUAGES;DIRECTORY"
|
||||||
|
""
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach (_lang ${ADD_PO_LANGUAGES})
|
||||||
|
set(_po_filename "${_lang}.po")
|
||||||
|
set(_po_filepath "${CMAKE_CURRENT_SOURCE_DIR}/${ADD_PO_DIRECTORY}/${_po_filename}")
|
||||||
|
set(_qm_filename "strawberry_${_lang}.qm")
|
||||||
|
set(_qm_filepath "${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/${_qm_filename}")
|
||||||
|
|
||||||
|
# Convert the .po files to .qm files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${_qm_filepath}
|
||||||
|
COMMAND ${QT_LCONVERT_EXECUTABLE} ARGS ${_po_filepath} -o ${_qm_filepath} -of qm
|
||||||
|
DEPENDS ${_po_filepath} ${_po_filepath}
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND ${outfiles} ${_qm_filepath})
|
||||||
|
endforeach (_lang)
|
||||||
|
|
||||||
|
# Generate a qrc file for the translations
|
||||||
|
set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/translations.qrc)
|
||||||
|
file(WRITE ${_qrc} "<RCC><qresource prefix=\"/${ADD_PO_DIRECTORY}\">")
|
||||||
|
foreach(_lang ${ADD_PO_LANGUAGES})
|
||||||
|
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
|
||||||
|
endforeach(_lang)
|
||||||
|
file(APPEND ${_qrc} "</qresource></RCC>")
|
||||||
|
qt5_add_resources(${outfiles} ${_qrc})
|
||||||
|
endmacro(add_po)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||||
set(STRAWBERRY_VERSION_MINOR 5)
|
set(STRAWBERRY_VERSION_MINOR 5)
|
||||||
set(STRAWBERRY_VERSION_PATCH 2)
|
set(STRAWBERRY_VERSION_PATCH 3)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION OFF)
|
||||||
@@ -84,8 +84,8 @@ if(GIT_REVISION)
|
|||||||
set(STRAWBERRY_VERSION_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
set(STRAWBERRY_VERSION_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||||
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
|
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
|
||||||
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||||
set(STRAWBERRY_VERSION_PAC_V "${GIT_TAGNAME}")
|
set(STRAWBERRY_VERSION_PAC_V "${GIT_TAGNAME}.r${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||||
set(STRAWBERRY_VERSION_PAC_R "${GIT_COMMITCOUNT}")
|
set(STRAWBERRY_VERSION_PAC_R "1")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
<file>schema/schema-3.sql</file>
|
<file>schema/schema-3.sql</file>
|
||||||
<file>schema/device-schema.sql</file>
|
<file>schema/device-schema.sql</file>
|
||||||
<file>style/strawberry.css</file>
|
<file>style/strawberry.css</file>
|
||||||
<file>misc/playing_tooltip.txt</file>
|
<file>html/playing-tooltip-plain.html</file>
|
||||||
<file>misc/oauthsuccess.html</file>
|
<file>html/playing-tooltip-table.html</file>
|
||||||
|
<file>html/oauthsuccess.html</file>
|
||||||
<file>pictures/strawberry.png</file>
|
<file>pictures/strawberry.png</file>
|
||||||
<file>pictures/strawberry-faded.png</file>
|
<file>pictures/strawberry-faded.png</file>
|
||||||
<file>pictures/noalbumart.png</file>
|
|
||||||
<file>pictures/nomusic.png</file>
|
<file>pictures/nomusic.png</file>
|
||||||
|
<file>pictures/cdcase.png</file>
|
||||||
<file>pictures/musicbrainz.png</file>
|
<file>pictures/musicbrainz.png</file>
|
||||||
<file>pictures/tiny-play.png</file>
|
<file>pictures/tiny-play.png</file>
|
||||||
<file>pictures/tiny-pause.png</file>
|
<file>pictures/tiny-pause.png</file>
|
||||||
@@ -28,7 +29,8 @@
|
|||||||
<file>pictures/osd_background.png</file>
|
<file>pictures/osd_background.png</file>
|
||||||
<file>pictures/osd_shadow_corner.png</file>
|
<file>pictures/osd_shadow_corner.png</file>
|
||||||
<file>pictures/osd_shadow_edge.png</file>
|
<file>pictures/osd_shadow_edge.png</file>
|
||||||
<file>pictures/deezer.png</file>
|
<file>pictures/nyancat.png</file>
|
||||||
<file>fonts/HumongousofEternitySt.ttf</file>
|
<file>pictures/rainbowdash.png</file>
|
||||||
|
<file>fonts/HumongousofEternitySt.ttf</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
8
data/html/playing-tooltip-plain.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<h4>%appName</h4>
|
||||||
|
<p>
|
||||||
|
%image<br />
|
||||||
|
%titleKey: %titleValue<br />
|
||||||
|
%artistKey: %artistValue<br />
|
||||||
|
%albumKey: %albumValue<br />
|
||||||
|
%lengthKey: %lengthValue<br />
|
||||||
|
</p>
|
||||||
@@ -63,7 +63,6 @@
|
|||||||
<file>icons/128x128/media-rewind.png</file>
|
<file>icons/128x128/media-rewind.png</file>
|
||||||
<file>icons/128x128/media-stop.png</file>
|
<file>icons/128x128/media-stop.png</file>
|
||||||
<file>icons/128x128/nvidia.png</file>
|
<file>icons/128x128/nvidia.png</file>
|
||||||
<file>icons/128x128/play2.png</file>
|
|
||||||
<file>icons/128x128/realtek.png</file>
|
<file>icons/128x128/realtek.png</file>
|
||||||
<file>icons/128x128/search.png</file>
|
<file>icons/128x128/search.png</file>
|
||||||
<file>icons/128x128/soundcard.png</file>
|
<file>icons/128x128/soundcard.png</file>
|
||||||
@@ -85,7 +84,6 @@
|
|||||||
<file>icons/128x128/zoom-in.png</file>
|
<file>icons/128x128/zoom-in.png</file>
|
||||||
<file>icons/128x128/zoom-out.png</file>
|
<file>icons/128x128/zoom-out.png</file>
|
||||||
<file>icons/128x128/tidal.png</file>
|
<file>icons/128x128/tidal.png</file>
|
||||||
<file>icons/128x128/deezer.png</file>
|
|
||||||
<file>icons/128x128/scrobble.png</file>
|
<file>icons/128x128/scrobble.png</file>
|
||||||
<file>icons/128x128/scrobble-disabled.png</file>
|
<file>icons/128x128/scrobble-disabled.png</file>
|
||||||
<file>icons/64x64/albums.png</file>
|
<file>icons/64x64/albums.png</file>
|
||||||
@@ -151,7 +149,6 @@
|
|||||||
<file>icons/64x64/media-rewind.png</file>
|
<file>icons/64x64/media-rewind.png</file>
|
||||||
<file>icons/64x64/media-stop.png</file>
|
<file>icons/64x64/media-stop.png</file>
|
||||||
<file>icons/64x64/nvidia.png</file>
|
<file>icons/64x64/nvidia.png</file>
|
||||||
<file>icons/64x64/play2.png</file>
|
|
||||||
<file>icons/64x64/pulseaudio.png</file>
|
<file>icons/64x64/pulseaudio.png</file>
|
||||||
<file>icons/64x64/realtek.png</file>
|
<file>icons/64x64/realtek.png</file>
|
||||||
<file>icons/64x64/search.png</file>
|
<file>icons/64x64/search.png</file>
|
||||||
@@ -173,7 +170,6 @@
|
|||||||
<file>icons/64x64/zoom-in.png</file>
|
<file>icons/64x64/zoom-in.png</file>
|
||||||
<file>icons/64x64/zoom-out.png</file>
|
<file>icons/64x64/zoom-out.png</file>
|
||||||
<file>icons/64x64/tidal.png</file>
|
<file>icons/64x64/tidal.png</file>
|
||||||
<file>icons/64x64/deezer.png</file>
|
|
||||||
<file>icons/64x64/scrobble.png</file>
|
<file>icons/64x64/scrobble.png</file>
|
||||||
<file>icons/64x64/scrobble-disabled.png</file>
|
<file>icons/64x64/scrobble-disabled.png</file>
|
||||||
<file>icons/48x48/albums.png</file>
|
<file>icons/48x48/albums.png</file>
|
||||||
@@ -242,7 +238,6 @@
|
|||||||
<file>icons/48x48/media-rewind.png</file>
|
<file>icons/48x48/media-rewind.png</file>
|
||||||
<file>icons/48x48/media-stop.png</file>
|
<file>icons/48x48/media-stop.png</file>
|
||||||
<file>icons/48x48/nvidia.png</file>
|
<file>icons/48x48/nvidia.png</file>
|
||||||
<file>icons/48x48/play2.png</file>
|
|
||||||
<file>icons/48x48/pulseaudio.png</file>
|
<file>icons/48x48/pulseaudio.png</file>
|
||||||
<file>icons/48x48/realtek.png</file>
|
<file>icons/48x48/realtek.png</file>
|
||||||
<file>icons/48x48/search.png</file>
|
<file>icons/48x48/search.png</file>
|
||||||
@@ -332,7 +327,6 @@
|
|||||||
<file>icons/32x32/media-rewind.png</file>
|
<file>icons/32x32/media-rewind.png</file>
|
||||||
<file>icons/32x32/media-stop.png</file>
|
<file>icons/32x32/media-stop.png</file>
|
||||||
<file>icons/32x32/nvidia.png</file>
|
<file>icons/32x32/nvidia.png</file>
|
||||||
<file>icons/32x32/play2.png</file>
|
|
||||||
<file>icons/32x32/pulseaudio.png</file>
|
<file>icons/32x32/pulseaudio.png</file>
|
||||||
<file>icons/32x32/realtek.png</file>
|
<file>icons/32x32/realtek.png</file>
|
||||||
<file>icons/32x32/search.png</file>
|
<file>icons/32x32/search.png</file>
|
||||||
@@ -355,7 +349,6 @@
|
|||||||
<file>icons/32x32/zoom-in.png</file>
|
<file>icons/32x32/zoom-in.png</file>
|
||||||
<file>icons/32x32/zoom-out.png</file>
|
<file>icons/32x32/zoom-out.png</file>
|
||||||
<file>icons/32x32/tidal.png</file>
|
<file>icons/32x32/tidal.png</file>
|
||||||
<file>icons/32x32/deezer.png</file>
|
|
||||||
<file>icons/32x32/scrobble.png</file>
|
<file>icons/32x32/scrobble.png</file>
|
||||||
<file>icons/32x32/scrobble-disabled.png</file>
|
<file>icons/32x32/scrobble-disabled.png</file>
|
||||||
<file>icons/22x22/albums.png</file>
|
<file>icons/22x22/albums.png</file>
|
||||||
@@ -424,7 +417,6 @@
|
|||||||
<file>icons/22x22/media-rewind.png</file>
|
<file>icons/22x22/media-rewind.png</file>
|
||||||
<file>icons/22x22/media-stop.png</file>
|
<file>icons/22x22/media-stop.png</file>
|
||||||
<file>icons/22x22/nvidia.png</file>
|
<file>icons/22x22/nvidia.png</file>
|
||||||
<file>icons/22x22/play2.png</file>
|
|
||||||
<file>icons/22x22/pulseaudio.png</file>
|
<file>icons/22x22/pulseaudio.png</file>
|
||||||
<file>icons/22x22/realtek.png</file>
|
<file>icons/22x22/realtek.png</file>
|
||||||
<file>icons/22x22/search.png</file>
|
<file>icons/22x22/search.png</file>
|
||||||
@@ -447,7 +439,6 @@
|
|||||||
<file>icons/22x22/zoom-in.png</file>
|
<file>icons/22x22/zoom-in.png</file>
|
||||||
<file>icons/22x22/zoom-out.png</file>
|
<file>icons/22x22/zoom-out.png</file>
|
||||||
<file>icons/22x22/tidal.png</file>
|
<file>icons/22x22/tidal.png</file>
|
||||||
<file>icons/22x22/deezer.png</file>
|
|
||||||
<file>icons/22x22/scrobble.png</file>
|
<file>icons/22x22/scrobble.png</file>
|
||||||
<file>icons/22x22/scrobble-disabled.png</file>
|
<file>icons/22x22/scrobble-disabled.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 23 KiB |
BIN
data/pictures/cdcase.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 12 KiB |
BIN
data/pictures/nyancat.png
Normal file
|
After Width: | Height: | Size: 850 B |
BIN
data/pictures/rainbowdash.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
4
dist/CMakeLists.txt
vendored
@@ -20,8 +20,8 @@ if (UNIX AND NOT APPLE)
|
|||||||
install(FILES ../data/icons/64x64/strawberry.png DESTINATION share/icons/hicolor/64x64/apps/)
|
install(FILES ../data/icons/64x64/strawberry.png DESTINATION share/icons/hicolor/64x64/apps/)
|
||||||
install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/)
|
install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/)
|
||||||
install(FILES ../data/icons/128x128/strawberry.svg DESTINATION share/icons/hicolor/scalable/apps/)
|
install(FILES ../data/icons/128x128/strawberry.svg DESTINATION share/icons/hicolor/scalable/apps/)
|
||||||
install(FILES unix/strawberry.desktop DESTINATION share/applications)
|
install(FILES unix/org.strawbs.strawberry.desktop DESTINATION share/applications)
|
||||||
install(FILES unix/strawberry.appdata.xml DESTINATION share/metainfo)
|
install(FILES unix/org.strawbs.strawberry.appdata.xml DESTINATION share/metainfo)
|
||||||
install(FILES man/strawberry.1 man/strawberry-tagreader.1 DESTINATION share/man/man1)
|
install(FILES man/strawberry.1 man/strawberry-tagreader.1 DESTINATION share/man/man1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
6
dist/debian/control
vendored
@@ -19,7 +19,7 @@ Build-Depends: debhelper (>= 7),
|
|||||||
qtbase5-dev,
|
qtbase5-dev,
|
||||||
qtbase5-dev-tools,
|
qtbase5-dev-tools,
|
||||||
qtbase5-private-dev,
|
qtbase5-private-dev,
|
||||||
qt5-dev-tools,
|
qttools5-dev,
|
||||||
libqt5x11extras5-dev,
|
libqt5x11extras5-dev,
|
||||||
libgstreamer1.0-dev,
|
libgstreamer1.0-dev,
|
||||||
libgstreamer-plugins-base1.0-dev,
|
libgstreamer-plugins-base1.0-dev,
|
||||||
@@ -47,7 +47,7 @@ Depends: ${shlibs:Depends},
|
|||||||
gstreamer1.0-pulseaudio
|
gstreamer1.0-pulseaudio
|
||||||
Homepage: http://www.strawbs.org/
|
Homepage: http://www.strawbs.org/
|
||||||
Description: Audio player and music collection organizer
|
Description: Audio player and music collection organizer
|
||||||
Strawberry is a audio player aimed at music collectors, audio enthusiasts and audiophiles.
|
Strawberry is a music player aimed at music collectors, audio enthusiasts and audiophiles.
|
||||||
.
|
.
|
||||||
Features:
|
Features:
|
||||||
- Play and organize music
|
- Play and organize music
|
||||||
@@ -59,7 +59,7 @@ Description: Audio player and music collection organizer
|
|||||||
- Edit tags on music files
|
- Edit tags on music files
|
||||||
- Fetch tags from MusicBrainz
|
- Fetch tags from MusicBrainz
|
||||||
- Album cover art from Lastfm, Musicbrainz and Discogs
|
- Album cover art from Lastfm, Musicbrainz and Discogs
|
||||||
- Song lyrics from AudD and API Seeds
|
- Song lyrics from AudD
|
||||||
- Support for multiple backends
|
- Support for multiple backends
|
||||||
- Audio analyzer
|
- Audio analyzer
|
||||||
- Audio equalizer
|
- Audio equalizer
|
||||||
|
|||||||
435
dist/debian/copyright
vendored
@@ -8,184 +8,179 @@ Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
|||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/timeconstants.h
|
Files: src/core/timeconstants.h
|
||||||
ext/libstrawberry-common/core/logging.cpp
|
ext/libstrawberry-common/core/logging.cpp
|
||||||
ext/libstrawberry-common/core/logging.h
|
ext/libstrawberry-common/core/logging.h
|
||||||
ext/libstrawberry-common/core/messagehandler.cpp
|
ext/libstrawberry-common/core/messagehandler.cpp
|
||||||
ext/libstrawberry-common/core/messagehandler.h
|
ext/libstrawberry-common/core/messagehandler.h
|
||||||
ext/libstrawberry-common/core/override.h
|
ext/libstrawberry-common/core/override.h
|
||||||
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
||||||
License: Apache-2.0
|
License: Apache-2.0
|
||||||
|
|
||||||
Files: src/core/main.h
|
Files: src/core/main.h
|
||||||
src/config.h.in
|
src/config.h.in
|
||||||
src/version.h.in
|
src/version.h.in
|
||||||
src/context/contextview.cpp
|
src/context/contextview.cpp
|
||||||
src/context/contextview.h
|
src/context/contextview.h
|
||||||
src/engine/enginetype.cpp
|
src/engine/enginetype.cpp
|
||||||
src/engine/enginetype.h
|
src/engine/enginetype.h
|
||||||
src/engine/alsadevicefinder.cpp
|
src/engine/alsadevicefinder.cpp
|
||||||
src/engine/alsadevicefinder.h
|
src/engine/alsadevicefinder.h
|
||||||
src/engine/deezerengine.cpp
|
src/engine/devicefinder.cpp
|
||||||
src/engine/deezerengine.h
|
src/engine/devicefinder.h
|
||||||
src/engine/devicefinder.cpp
|
src/engine/enginedevice.cpp
|
||||||
src/engine/devicefinder.h
|
src/engine/enginedevice.h
|
||||||
src/engine/enginedevice.cpp
|
src/engine/phononengine.cpp
|
||||||
src/engine/enginedevice.h
|
src/engine/phononengine.h
|
||||||
src/engine/phononengine.cpp
|
src/internet/internetservice.cpp
|
||||||
src/engine/phononengine.h
|
src/internet/internetservice.h
|
||||||
src/internet/internetservice.cpp
|
src/settings/backendsettingspage.cpp
|
||||||
src/internet/internetservice.h
|
src/settings/backendsettingspage.h
|
||||||
src/settings/backendsettingspage.cpp
|
src/settings/scrobblersettingspage.cpp
|
||||||
src/settings/backendsettingspage.h
|
src/settings/scrobblersettingspage.h
|
||||||
src/settings/scrobblersettingspage.cpp
|
src/settings/tidalsettingspage.cpp
|
||||||
src/settings/scrobblersettingspage.h
|
src/settings/tidalsettingspage.h
|
||||||
src/settings/deezersettingspage.cpp
|
src/covermanager/lastfmcoverprovider.cpp
|
||||||
src/settings/deezersettingspage.h
|
src/covermanager/lastfmcoverprovider.h
|
||||||
src/settings/tidalsettingspage.cpp
|
src/covermanager/musicbrainzcoverprovider.cpp
|
||||||
src/settings/tidalsettingspage.h
|
src/covermanager/musicbrainzcoverprovider.h
|
||||||
src/covermanager/lastfmcoverprovider.cpp
|
src/globalshortcuts/globalshortcutbackend-system.cpp
|
||||||
src/covermanager/lastfmcoverprovider.h
|
src/globalshortcuts/globalshortcutbackend-system.h
|
||||||
src/covermanager/musicbrainzcoverprovider.cpp
|
src/globalshortcuts/globalshortcut.cpp
|
||||||
src/covermanager/musicbrainzcoverprovider.h
|
src/globalshortcuts/globalshortcut.h
|
||||||
src/globalshortcuts/globalshortcutbackend-system.cpp
|
src/globalshortcuts/globalshortcut-X11.cpp
|
||||||
src/globalshortcuts/globalshortcutbackend-system.h
|
src/globalshortcuts/globalshortcut-win.cpp
|
||||||
src/globalshortcuts/globalshortcut.cpp
|
src/globalshortcuts/keymapper_x11.h
|
||||||
src/globalshortcuts/globalshortcut.h
|
src/globalshortcuts/keymapper_win.h
|
||||||
src/globalshortcuts/globalshortcut-X11.cpp
|
src/lyrics/*
|
||||||
src/globalshortcuts/globalshortcut-win.cpp
|
src/scrobbler/*
|
||||||
src/globalshortcuts/keymapper_x11.h
|
src/tidal/*
|
||||||
src/globalshortcuts/keymapper_win.h
|
src/transcoder/transcoderoptionswavpack.cpp
|
||||||
src/lyrics/*
|
src/transcoder/transcoderoptionswavpack.h
|
||||||
src/scrobbler/*
|
|
||||||
src/tidal/*
|
|
||||||
src/deezer/*
|
|
||||||
transcoderoptionswavpack.cpp
|
|
||||||
transcoderoptionswavpack.h
|
|
||||||
Copyright: 2012-2014, 2017-2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2012-2014, 2017-2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/main.cpp
|
Files: src/core/main.cpp
|
||||||
src/core/mainwindow.cpp
|
src/core/mainwindow.cpp
|
||||||
src/core/mainwindow.h
|
src/core/mainwindow.h
|
||||||
src/core/player.cpp
|
src/core/player.cpp
|
||||||
src/core/player.h
|
src/core/player.h
|
||||||
src/core/song.cpp
|
src/core/song.cpp
|
||||||
src/core/song.h
|
src/core/song.h
|
||||||
src/core/urlhandler.cpp
|
src/core/urlhandler.cpp
|
||||||
src/core/urlhandler.h
|
src/core/urlhandler.h
|
||||||
src/core/utilities.cpp
|
src/core/utilities.cpp
|
||||||
src/core/utilities.h
|
src/core/utilities.h
|
||||||
src/core/iconloader.cpp
|
src/core/iconloader.cpp
|
||||||
src/core/iconloader.h
|
src/core/iconloader.h
|
||||||
src/engine/gstenginepipeline.cpp
|
src/engine/gstenginepipeline.cpp
|
||||||
src/engine/gstenginepipeline.h
|
src/engine/gstenginepipeline.h
|
||||||
src/engine/vlcengine.cpp
|
src/engine/vlcengine.cpp
|
||||||
src/engine/vlcengine.h
|
src/engine/vlcengine.h
|
||||||
src/context/contextalbumsmodel.cpp
|
src/context/contextalbumsmodel.cpp
|
||||||
src/context/contextalbumsview.cpp
|
src/context/contextalbumsview.cpp
|
||||||
src/context/contextalbumsmodel.h
|
src/context/contextalbumsmodel.h
|
||||||
src/context/contextalbumsview.h
|
src/context/contextalbumsview.h
|
||||||
src/widgets/playingwidget.cpp
|
src/widgets/playingwidget.cpp
|
||||||
src/widgets/playingwidget.h
|
src/widgets/playingwidget.h
|
||||||
src/dialogs/about.cpp
|
src/dialogs/about.cpp
|
||||||
src/dialogs/about.h
|
src/dialogs/about.h
|
||||||
src/playlist/playlistitem.cpp
|
src/playlist/playlistitem.cpp
|
||||||
src/playlist/playlistitem.h
|
src/playlist/playlistitem.h
|
||||||
src/playlist/playlistdelegates.cpp
|
src/playlist/playlistdelegates.cpp
|
||||||
src/playlist/playlistdelegates.h
|
src/playlist/playlistdelegates.h
|
||||||
src/internet/internetplaylistitem.cpp
|
src/internet/internetplaylistitem.cpp
|
||||||
src/internet/internetsearch.cpp
|
src/internet/internetsearch.cpp
|
||||||
src/internet/internetsearch.h
|
src/internet/internetsearch.h
|
||||||
src/internet/internetsearchview.cpp
|
src/internet/internetsearchview.cpp
|
||||||
src/internet/internetsearchview.h
|
src/internet/internetsearchview.h
|
||||||
src/internet/internetservices.cpp
|
src/internet/internetservices.cpp
|
||||||
src/internet/internetservices.h
|
src/internet/internetservices.h
|
||||||
ext/libstrawberry-tagreader/tagreader.cpp
|
ext/libstrawberry-tagreader/tagreader.cpp
|
||||||
ext/libstrawberry-tagreader/tagreader.h
|
ext/libstrawberry-tagreader/tagreader.h
|
||||||
src/device/devicemanager.cpp
|
src/device/devicemanager.cpp
|
||||||
src/device/devicemanager.h
|
src/device/devicemanager.h
|
||||||
src/device/deviceinfo.cpp
|
src/device/deviceinfo.cpp
|
||||||
src/device/deviceinfo.h
|
src/device/deviceinfo.h
|
||||||
src/device/deviceproperties.cpp
|
src/device/deviceproperties.cpp
|
||||||
src/device/deviceproperties.h
|
src/device/deviceproperties.h
|
||||||
src/device/deviceview.cpp
|
src/device/deviceview.cpp
|
||||||
src/device/deviceview.h
|
src/device/deviceview.h
|
||||||
src/device/connecteddevice.cpp
|
src/device/connecteddevice.cpp
|
||||||
src/device/connecteddevice.h
|
src/device/connecteddevice.h
|
||||||
src/globalshortcuts/globalshortcuts.cpp
|
src/globalshortcuts/globalshortcuts.cpp
|
||||||
src/globalshortcuts/globalshortcuts.h
|
src/globalshortcuts/globalshortcuts.h
|
||||||
src/settings/shortcutssettingspage.cpp
|
src/settings/shortcutssettingspage.cpp
|
||||||
src/settings/shortcutssettingspage.h
|
src/settings/shortcutssettingspage.h
|
||||||
src/organise/organise.cpp
|
src/organise/organise.cpp
|
||||||
src/organise/organise.h
|
src/organise/organise.h
|
||||||
src/organise/organisedialog.cpp
|
src/organise/organisedialog.cpp
|
||||||
src/organise/organisedialog.h
|
src/organise/organisedialog.h
|
||||||
src/organise/organiseerrordialog.cpp
|
src/organise/organiseerrordialog.cpp
|
||||||
src/organise/organiseerrordialog.h
|
src/organise/organiseerrordialog.h
|
||||||
src/transcoder/transcoder.cpp
|
src/transcoder/transcoder.cpp
|
||||||
src/transcoder/transcoder.h
|
src/transcoder/transcoder.h
|
||||||
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
|
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
|
||||||
2012-2014, 2017-2018 Jonas Kvinge <jonas@jkvinge.net>
|
2012-2014, 2017-2018 Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/engine/enginebase.cpp
|
Files: src/engine/enginebase.cpp
|
||||||
src/engine/enginebase.h
|
src/engine/enginebase.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2010, David Sansome <me@davidsansome.com>
|
2010, David Sansome <me@davidsansome.com>
|
||||||
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/engine/gstengine.cpp
|
Files: src/engine/gstengine.cpp
|
||||||
src/engine/gstengine.h
|
src/engine/gstengine.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2006, Paul Cifarelli <paul@cifarelli.net>
|
2006, Paul Cifarelli <paul@cifarelli.net>
|
||||||
2005, Jakub Stachowski <qbast@go2.pl>
|
2005, Jakub Stachowski <qbast@go2.pl>
|
||||||
2003-2005, Mark Kretschmann <markey@web.de>
|
2003-2005, Mark Kretschmann <markey@web.de>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/engine/xineengine.cpp
|
Files: src/engine/xineengine.cpp
|
||||||
src/engine/xineengine.h
|
src/engine/xineengine.h
|
||||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
2005, Ian Monroe <ian@monroe.nu>
|
2005, Ian Monroe <ian@monroe.nu>
|
||||||
2005, Christophe Thommeret <hftom@free.fr>
|
2005, Christophe Thommeret <hftom@free.fr>
|
||||||
2005, 2006, Mark Kretschmann <markey@web.de>
|
2005, 2006, Mark Kretschmann <markey@web.de>
|
||||||
2004, 2005, Max Howell <max.howell@methylblue.com>
|
2004, 2005, Max Howell <max.howell@methylblue.com>
|
||||||
2003, 2004, J. Kofler <kaffeine@gmx.net>
|
2003, 2004, J. Kofler <kaffeine@gmx.net>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/engine/xinescope.c
|
Files: src/engine/xinescope.c
|
||||||
src/engine/xinescope.h
|
src/engine/xinescope.h
|
||||||
Copyright: 2004, Max Howell <max.howell@methylblue.com>
|
Copyright: 2004, Max Howell <max.howell@methylblue.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/widgets/fancytabwidget.cpp
|
Files: src/widgets/fancytabwidget.cpp
|
||||||
src/widgets/fancytabwidget.h
|
src/widgets/fancytabwidget.h
|
||||||
Copyright: 2018, Vikram Ambrose <ambroseworks@gmail.com>
|
Copyright: 2018, Vikram Ambrose <ambroseworks@gmail.com>
|
||||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/application.cpp
|
Files: src/core/application.cpp
|
||||||
src/core/application.h
|
src/core/application.h
|
||||||
Copyright: 2012, David Sansome <me@davidsansome.com>
|
Copyright: 2012, David Sansome <me@davidsansome.com>
|
||||||
2012, 2014, John Maguire <john.maguire@gmail.com>
|
2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/appearance.cpp
|
Files: src/core/appearance.cpp
|
||||||
src/core/appearance.h
|
src/core/appearance.h
|
||||||
Copyright: 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
Copyright: 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/covermanager/discogscoverprovider.cpp
|
Files: src/covermanager/discogscoverprovider.cpp
|
||||||
src/covermanager/discogscoverprovider.h
|
src/covermanager/discogscoverprovider.h
|
||||||
Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
|
Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
|
||||||
2016, Jonas Kvinge <jonas@jkvinge.net>
|
2016, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: ext/libstrawberry-common/core/arraysize.h
|
Files: ext/libstrawberry-common/core/arraysize.h
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
|
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
|
||||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
|
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||||
License: BSD-style
|
License: BSD-style
|
||||||
|
|
||||||
@@ -194,19 +189,47 @@ Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
|||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/analyzer/fht.cpp
|
Files: src/analyzer/fht.cpp
|
||||||
src/analyzer/fht.h
|
src/analyzer/fht.h
|
||||||
Copyright: 2004, Melchior FRANZ - mfranz@kde.org
|
Copyright: 2004, Melchior FRANZ <mfranz@kde.org>
|
||||||
|
2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
2017, Santiago Gil
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/analyzer/analyzerbase.cpp
|
Files: src/analyzer/analyzerbase.cpp
|
||||||
src/analyzer/analyzerbase.h
|
src/analyzer/analyzerbase.h
|
||||||
Copyright: 2003-2005, Max Howell <max.howell@methylblue.com>
|
Copyright: 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||||
|
2009-2012, David Sansome <me@davidsansome.com>
|
||||||
|
2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
2017, Santiago Gil
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/analyzer/blockanalyzer.cpp
|
Files: src/analyzer/blockanalyzer.cpp
|
||||||
src/analyzer/blockanalyzer.h
|
src/analyzer/blockanalyzer.h
|
||||||
Copyright: 2003-2005, Max Howell <max.howell@methylblue.com>
|
Copyright: 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||||
2005, Mark Kretschmann <markey@web.de>
|
2005, Mark Kretschmann <markey@web.de>
|
||||||
|
2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
License: GPL-2+
|
||||||
|
|
||||||
|
Files: src/analyzer/boomanalyzer.cpp
|
||||||
|
src/analyzer/boomanalyzer.h
|
||||||
|
Copyright: 2004, Max Howell <max.howell@methylblue.com>
|
||||||
|
2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
License: GPL-2+
|
||||||
|
|
||||||
|
Files: src/analyzer/rainbowanalyzer.cpp
|
||||||
|
src/analyzer/rainbowanalyzer.h
|
||||||
|
Copyright: 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
||||||
|
2011-2012, 2014, David Sansome <me@davidsansome.com>
|
||||||
|
2011, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||||
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/collection/savedgroupingmanager.h
|
Files: src/collection/savedgroupingmanager.h
|
||||||
@@ -214,53 +237,53 @@ Copyright: 2015, Nick Lanham <nick@afternight.org>
|
|||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/core/scoped_cftyperef.h
|
Files: src/core/scoped_cftyperef.h
|
||||||
src/core/scoped_nsobject.h
|
src/core/scoped_nsobject.h
|
||||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||||
License: BSD-style
|
License: BSD-style
|
||||||
|
|
||||||
Files: src/core/signalchecker.cpp
|
Files: src/core/signalchecker.cpp
|
||||||
Copyright: 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
Copyright: 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
2012, 2014, John Maguire <john.maguire@gmail.com>
|
2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2010, David Sansome <me@davidsansome.com>
|
2010, David Sansome <me@davidsansome.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/device/udisks2lister.cpp
|
Files: src/device/udisks2lister.cpp
|
||||||
src/device/udisks2lister.h
|
src/device/udisks2lister.h
|
||||||
Copyright: 2016, Valeriy Malov <jazzvoid@gmail.com>
|
Copyright: 2016, Valeriy Malov <jazzvoid@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/internet/localredirectserver.cpp
|
Files: src/internet/localredirectserver.cpp
|
||||||
src/internet/localredirectserver.h
|
src/internet/localredirectserver.h
|
||||||
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/transcoder/transcoderoptionsopus.cpp
|
Files: src/transcoder/transcoderoptionsopus.cpp
|
||||||
src/transcoder/transcoderoptionsopus.h
|
src/transcoder/transcoderoptionsopus.h
|
||||||
Copyright: 2013, Martin Brodbeck <martin@brodbeck-online.de>
|
Copyright: 2013, Martin Brodbeck <martin@brodbeck-online.de>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/widgets/clickablelabel.cpp
|
Files: src/widgets/clickablelabel.cpp
|
||||||
src/widgets/clickablelabel.h
|
src/widgets/clickablelabel.h
|
||||||
src/widgets/renametablineedit.cpp
|
src/widgets/renametablineedit.cpp
|
||||||
src/widgets/renametablineedit.h
|
src/widgets/renametablineedit.h
|
||||||
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: src/widgets/sliderwidget.cpp
|
Files: src/widgets/sliderwidget.cpp
|
||||||
src/widgets/sliderwidget.h
|
src/widgets/sliderwidget.h
|
||||||
Copyright: 2005, Gábor Lehel
|
Copyright: 2005, Gábor Lehel
|
||||||
2003, Mark Kretschmann <markey@web.de>
|
2003, Mark Kretschmann <markey@web.de>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/widgets/stylehelper.cpp
|
Files: src/widgets/stylehelper.cpp
|
||||||
src/widgets/stylehelper.h
|
src/widgets/stylehelper.h
|
||||||
Copyright: 2010, Nokia Corporation and/or its subsidiary(-ies).
|
Copyright: 2010, Nokia Corporation and/or its subsidiary(-ies).
|
||||||
License: LGPL-2.1
|
License: LGPL-2.1
|
||||||
|
|
||||||
Files: 3rdparty/SPMediaKeyTap/*
|
Files: 3rdparty/SPMediaKeyTap/*
|
||||||
Copyright: 2010, Spotify AB
|
Copyright: 2010, Spotify AB
|
||||||
Copyright: 2011, Joachim Bengtsson
|
2011, Joachim Bengtsson
|
||||||
License: BSD-3-clause
|
License: BSD-3-clause
|
||||||
|
|
||||||
Files: 3rdparty/qocoa/*
|
Files: 3rdparty/qocoa/*
|
||||||
@@ -280,21 +303,21 @@ Copyright: 2003-2005, Allan Sandfeld Jensen
|
|||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/ape/apefile.cpp
|
Files: 3rdparty/taglib/ape/apefile.cpp
|
||||||
3rdparty/taglib/ape/apefile.h
|
3rdparty/taglib/ape/apefile.h
|
||||||
Copyright: 2010, Alex Novichkov
|
Copyright: 2010, Alex Novichkov
|
||||||
2006, Lukáš Lalinský
|
2006, Lukáš Lalinský
|
||||||
2004, Allan Sandfeld Jensen
|
2004, Allan Sandfeld Jensen
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/ape/apefooter.cpp
|
Files: 3rdparty/taglib/ape/apefooter.cpp
|
||||||
Copyright: 2004, Allan Sandfeld Jensen
|
Copyright: 2004, Allan Sandfeld Jensen
|
||||||
2002-2008, Scott Wheeler (id3v2header.cpp)
|
2002-2008, Scott Wheeler (id3v2header.cpp)
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/ape/apeproperties.cpp
|
Files: 3rdparty/taglib/ape/apeproperties.cpp
|
||||||
3rdparty/taglib/ape/apeproperties.h
|
3rdparty/taglib/ape/apeproperties.h
|
||||||
Copyright: 2010, Alex Novichkov
|
Copyright: 2010, Alex Novichkov
|
||||||
2006, Lukáš Lalinský
|
2006, Lukáš Lalinský
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/asf/*
|
Files: 3rdparty/taglib/asf/*
|
||||||
@@ -302,7 +325,7 @@ Copyright: 2005-2007, 2009-2011, Lukáš Lalinský
|
|||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/asf/asfpicture.cpp
|
Files: 3rdparty/taglib/asf/asfpicture.cpp
|
||||||
3rdparty/taglib/asf/asfpicture.h
|
3rdparty/taglib/asf/asfpicture.h
|
||||||
Copyright: 2010, Anton Sergunov
|
Copyright: 2010, Anton Sergunov
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
@@ -320,23 +343,23 @@ License: LGPL-2.1 and/or MPL-1.1
|
|||||||
|
|
||||||
Files: 3rdparty/taglib/fileref.cpp
|
Files: 3rdparty/taglib/fileref.cpp
|
||||||
Copyright: 2010, Alex Novichkov
|
Copyright: 2010, Alex Novichkov
|
||||||
2002-2008, Scott Wheeler
|
2002-2008, Scott Wheeler
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/flac/*
|
Files: 3rdparty/taglib/flac/*
|
||||||
3rdparty/taglib/mp4/*
|
3rdparty/taglib/mp4/*
|
||||||
Copyright: 2005-2007, 2009-2011, Lukáš Lalinský
|
Copyright: 2005-2007, 2009-2011, Lukáš Lalinský
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/flac/flacfile.cpp
|
Files: 3rdparty/taglib/flac/flacfile.cpp
|
||||||
3rdparty/taglib/flac/flacfile.h
|
3rdparty/taglib/flac/flacfile.h
|
||||||
3rdparty/taglib/flac/flacproperties.cpp
|
3rdparty/taglib/flac/flacproperties.cpp
|
||||||
3rdparty/taglib/flac/flacproperties.h
|
3rdparty/taglib/flac/flacproperties.h
|
||||||
Copyright: 2003-2005, Allan Sandfeld Jensen
|
Copyright: 2003-2005, Allan Sandfeld Jensen
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/it/*
|
Files: 3rdparty/taglib/it/*
|
||||||
3rdparty/taglib/mod/*
|
3rdparty/taglib/mod/*
|
||||||
Copyright: 2011, Mathias Panzenböck
|
Copyright: 2011, Mathias Panzenböck
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
@@ -345,53 +368,53 @@ Copyright: 2003-2005, Allan Sandfeld Jensen
|
|||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/chapterframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/chapterframe.h
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
|
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/tableofcontentsframe.h
|
||||||
Copyright: 2013, Lukas Krejci
|
Copyright: 2013, Lukas Krejci
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/eventtimingcodesframe.h
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp
|
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/podcastframe.h
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
|
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h
|
||||||
Copyright: 2014, 2015, Urs Fleisch
|
Copyright: 2014, 2015, Urs Fleisch
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
||||||
Copyright: 2006, Aaron VonderHaar
|
Copyright: 2006, Aaron VonderHaar
|
||||||
2002-2008, Scott Wheeler
|
2002-2008, Scott Wheeler
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/ownershipframe.h
|
||||||
Copyright: 2012, Rupert Daniel
|
Copyright: 2012, Rupert Daniel
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/popularimeterframe.h
|
||||||
Copyright: 2008, 2011, Lukas Lalinsky
|
Copyright: 2008, 2011, Lukas Lalinsky
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/privateframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/privateframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/privateframe.h
|
||||||
Copyright: 2008, Serkan Kalyoncu
|
Copyright: 2008, Serkan Kalyoncu
|
||||||
2008, Scott Wheeler
|
2008, Scott Wheeler
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
Files: 3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp
|
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.cpp
|
||||||
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h
|
3rdparty/taglib/mpeg/id3v2/frames/urllinkframe.h
|
||||||
Copyright: 2006, Urs Fleisch
|
Copyright: 2006, Urs Fleisch
|
||||||
2002-2008, Scott Wheeler
|
2002-2008, Scott Wheeler
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/mpeg/xingheader.cpp
|
Files: 3rdparty/taglib/mpeg/xingheader.cpp
|
||||||
3rdparty/taglib/mpeg/xingheader.h
|
3rdparty/taglib/mpeg/xingheader.h
|
||||||
Copyright: 2003, Ismael Orenstein
|
Copyright: 2003, Ismael Orenstein
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
@@ -400,48 +423,48 @@ Copyright: 2003-2005, Allan Sandfeld Jensen
|
|||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/ogg/opus/*
|
Files: 3rdparty/taglib/ogg/opus/*
|
||||||
3rdparty/taglib/ogg/speex/*
|
3rdparty/taglib/ogg/speex/*
|
||||||
Copyright: 2006, 2012, Lukáš Lalinský
|
Copyright: 2006, 2012, Lukáš Lalinský
|
||||||
2002-2008, Scott Wheeler
|
2002-2008, Scott Wheeler
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/riff/riffutils.h
|
Files: 3rdparty/taglib/riff/riffutils.h
|
||||||
3rdparty/taglib/riff/wav/infotag.cpp
|
3rdparty/taglib/riff/wav/infotag.cpp
|
||||||
3rdparty/taglib/riff/wav/infotag.h
|
3rdparty/taglib/riff/wav/infotag.h
|
||||||
3rdparty/taglib/tagutils.cpp
|
3rdparty/taglib/tagutils.cpp
|
||||||
3rdparty/taglib/tagutils.h
|
3rdparty/taglib/tagutils.h
|
||||||
3rdparty/taglib/toolkit/tdebuglistener.cpp
|
3rdparty/taglib/toolkit/tdebuglistener.cpp
|
||||||
3rdparty/taglib/toolkit/tdebuglistener.h
|
3rdparty/taglib/toolkit/tdebuglistener.h
|
||||||
3rdparty/taglib/toolkit/trefcounter.cpp
|
3rdparty/taglib/toolkit/trefcounter.cpp
|
||||||
3rdparty/taglib/toolkit/trefcounter.h
|
3rdparty/taglib/toolkit/trefcounter.h
|
||||||
3rdparty/taglib/toolkit/tutils.h
|
3rdparty/taglib/toolkit/tutils.h
|
||||||
3rdparty/taglib/toolkit/tzlib.cpp
|
3rdparty/taglib/toolkit/tzlib.cpp
|
||||||
3rdparty/taglib/toolkit/tzlib.h
|
3rdparty/taglib/toolkit/tzlib.h
|
||||||
3rdparty/taglib/mpeg/mpegutils.h
|
3rdparty/taglib/mpeg/mpegutils.h
|
||||||
Copyright: 2012, 2013, 2015, 2016, Tsuda Kageyu
|
Copyright: 2012, 2013, 2015, 2016, Tsuda Kageyu
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/s3m/*
|
Files: 3rdparty/taglib/s3m/*
|
||||||
3rdparty/taglib/xm/*
|
3rdparty/taglib/xm/*
|
||||||
Copyright: 2011, Mathias Panzenböck
|
Copyright: 2011, Mathias Panzenböck
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/toolkit/tbytevectorstream.cpp
|
Files: 3rdparty/taglib/toolkit/tbytevectorstream.cpp
|
||||||
3rdparty/taglib/toolkit/tbytevectorstream.h
|
3rdparty/taglib/toolkit/tbytevectorstream.h
|
||||||
3rdparty/taglib/toolkit/tiostream.cpp
|
3rdparty/taglib/toolkit/tiostream.cpp
|
||||||
3rdparty/taglib/toolkit/tiostream.h
|
3rdparty/taglib/toolkit/tiostream.h
|
||||||
Copyright: 2008, 2011, Lukas Lalinsky
|
Copyright: 2008, 2011, Lukas Lalinsky
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/toolkit/tpropertymap.cpp
|
Files: 3rdparty/taglib/toolkit/tpropertymap.cpp
|
||||||
3rdparty/taglib/toolkit/tpropertymap.h
|
3rdparty/taglib/toolkit/tpropertymap.h
|
||||||
Copyright: 2012, Michael Helmling
|
Copyright: 2012, Michael Helmling
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/taglib/trueaudio/*
|
Files: 3rdparty/taglib/trueaudio/*
|
||||||
3rdparty/taglib/wavpack/*
|
3rdparty/taglib/wavpack/*
|
||||||
Copyright: 2006, Lukáš Lalinský
|
Copyright: 2006, Lukáš Lalinský
|
||||||
2004, Allan Sandfeld Jensen
|
2004, Allan Sandfeld Jensen
|
||||||
License: LGPL-2.1 and/or MPL-1.1
|
License: LGPL-2.1 and/or MPL-1.1
|
||||||
|
|
||||||
Files: 3rdparty/utf8-cpp/*
|
Files: 3rdparty/utf8-cpp/*
|
||||||
|
|||||||
3
dist/debian/rules
vendored
@@ -11,7 +11,8 @@ configure: configure-stamp
|
|||||||
configure-stamp:
|
configure-stamp:
|
||||||
dh_testdir
|
dh_testdir
|
||||||
cmake .. \
|
cmake .. \
|
||||||
-DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/strawberry/usr
|
-DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/strawberry/usr \
|
||||||
|
-DENABLE_TRANSLATIONS=ON
|
||||||
touch configure-stamp
|
touch configure-stamp
|
||||||
|
|
||||||
build: build-stamp
|
build: build-stamp
|
||||||
|
|||||||
17
dist/fedora/strawberry.spec.in
vendored
@@ -1,7 +1,7 @@
|
|||||||
Name: strawberry
|
Name: strawberry
|
||||||
Version: @STRAWBERRY_VERSION_RPM_V@
|
Version: @STRAWBERRY_VERSION_RPM_V@
|
||||||
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
||||||
Summary: A audio player and music collection organiser
|
Summary: A music player and collection organiser
|
||||||
Group: Applications/Multimedia
|
Group: Applications/Multimedia
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
URL: http://www.strawbs.org/
|
URL: http://www.strawbs.org/
|
||||||
@@ -15,6 +15,8 @@ BuildRequires: gcc-c++
|
|||||||
BuildRequires: hicolor-icon-theme
|
BuildRequires: hicolor-icon-theme
|
||||||
BuildRequires: make
|
BuildRequires: make
|
||||||
BuildRequires: git
|
BuildRequires: git
|
||||||
|
BuildRequires: gettext
|
||||||
|
BuildRequires: cmake(Qt5LinguistTools)
|
||||||
BuildRequires: pkgconfig
|
BuildRequires: pkgconfig
|
||||||
BuildRequires: pkgconfig(glib-2.0)
|
BuildRequires: pkgconfig(glib-2.0)
|
||||||
BuildRequires: pkgconfig(gio-2.0)
|
BuildRequires: pkgconfig(gio-2.0)
|
||||||
@@ -47,7 +49,7 @@ BuildRequires: pkgconfig(libnotify)
|
|||||||
BuildRequires: pkgconfig(libudf)
|
BuildRequires: pkgconfig(libudf)
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Strawberry is a audio player and music collection organizer.
|
Strawberry is a music player and collection organizer.
|
||||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
@@ -60,7 +62,7 @@ Features:
|
|||||||
* Edit tags on music files
|
* Edit tags on music files
|
||||||
* Fetch tags from MusicBrainz
|
* Fetch tags from MusicBrainz
|
||||||
* Album cover art from Last.fm, Musicbrainz and Discogs
|
* Album cover art from Last.fm, Musicbrainz and Discogs
|
||||||
* Song lyrics from AudD and API Seeds
|
* Song lyrics from AudD
|
||||||
* Support for multiple backends
|
* Support for multiple backends
|
||||||
* Audio analyzer
|
* Audio analyzer
|
||||||
* Audio equalizer
|
* Audio equalizer
|
||||||
@@ -83,6 +85,7 @@ pushd %{_target_platform}
|
|||||||
%{cmake} \
|
%{cmake} \
|
||||||
-DBUILD_WERROR:BOOL=OFF \
|
-DBUILD_WERROR:BOOL=OFF \
|
||||||
-DCMAKE_BUILD_TYPE:STRING=Release \
|
-DCMAKE_BUILD_TYPE:STRING=Release \
|
||||||
|
-DENABLE_TRANSLATIONS=ON \
|
||||||
..
|
..
|
||||||
popd
|
popd
|
||||||
|
|
||||||
@@ -93,8 +96,8 @@ make install DESTDIR=%{buildroot} -C %{_target_platform}
|
|||||||
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
||||||
|
|
||||||
%check
|
%check
|
||||||
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
|
desktop-file-validate %{buildroot}%{_datadir}/applications/org.strawbs.strawberry.desktop
|
||||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry.appdata.xml
|
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/org.strawbs.strawberry.appdata.xml
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
@@ -102,12 +105,12 @@ appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry
|
|||||||
%license COPYING
|
%license COPYING
|
||||||
%{_bindir}/strawberry
|
%{_bindir}/strawberry
|
||||||
%{_bindir}/strawberry-tagreader
|
%{_bindir}/strawberry-tagreader
|
||||||
%{_datadir}/applications/strawberry.desktop
|
%{_datadir}/applications/*.desktop
|
||||||
%{_datadir}/icons/hicolor/48x48/apps/strawberry.png
|
%{_datadir}/icons/hicolor/48x48/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
||||||
%{_datadir}/appdata/strawberry.appdata.xml
|
%{_datadir}/appdata/*.appdata.xml
|
||||||
%{_mandir}/man1/strawberry.1.*
|
%{_mandir}/man1/strawberry.1.*
|
||||||
%{_mandir}/man1/strawberry-tagreader.1.*
|
%{_mandir}/man1/strawberry-tagreader.1.*
|
||||||
|
|
||||||
|
|||||||
8
dist/macos/create-dmg.sh.in
vendored
@@ -3,14 +3,18 @@
|
|||||||
version="@STRAWBERRY_VERSION_PACKAGE@"
|
version="@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
echo "Usage: $0 <bundle.app>"
|
echo "Usage: $0 <bundle.app> (append)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
name=$(basename "$1" | perl -pe 's/(.*).app/\1/')
|
name=$(basename "$1" | perl -pe 's/(.*).app/\1/')
|
||||||
bundle_dir="$1"
|
bundle_dir="$1"
|
||||||
temp_dir="dmg/$name"
|
temp_dir="dmg/$name"
|
||||||
output_file="$name-$version.dmg"
|
if [ -z "$2" ]; then
|
||||||
|
output_file="$name-$version.dmg"
|
||||||
|
else
|
||||||
|
output_file="$name-$2-$version.dmg"
|
||||||
|
fi
|
||||||
|
|
||||||
rm -rf "$temp_dir"
|
rm -rf "$temp_dir"
|
||||||
rm -f "$output_file"
|
rm -f "$output_file"
|
||||||
|
|||||||
6
dist/man/strawberry.1
vendored
@@ -1,11 +1,11 @@
|
|||||||
.TH STRAWBERRY "1" "User Commands"
|
.TH STRAWBERRY "1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
Strawberry \- audio player and music collection organizer
|
Strawberry \- music player and music collection organizer
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B strawberry
|
.B strawberry
|
||||||
[\fI\,options\/\fR] [\fI\,URL(s)\/\fR]
|
[\fI\,options\/\fR] [\fI\,URL(s)\/\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Strawberry is a audio player especially aimed at audiophiles.
|
Strawberry is a music player especially aimed at audiophiles.
|
||||||
.TP
|
.TP
|
||||||
Features:
|
Features:
|
||||||
.br
|
.br
|
||||||
@@ -27,7 +27,7 @@ Features:
|
|||||||
.br
|
.br
|
||||||
- Album cover art from Lastfm, Musicbrainz and Discogs
|
- Album cover art from Lastfm, Musicbrainz and Discogs
|
||||||
.br
|
.br
|
||||||
- Song lyrics from AudD and API Seeds
|
- Song lyrics from AudD
|
||||||
.br
|
.br
|
||||||
- Support for multiple backends
|
- Support for multiple backends
|
||||||
.br
|
.br
|
||||||
|
|||||||
25
dist/opensuse/strawberry.spec.in
vendored
@@ -1,7 +1,7 @@
|
|||||||
Name: strawberry
|
Name: strawberry
|
||||||
Version: @STRAWBERRY_VERSION_RPM_V@
|
Version: @STRAWBERRY_VERSION_RPM_V@
|
||||||
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
|
||||||
Summary: A audio player and music collection organiser
|
Summary: A music player and collection organiser
|
||||||
Group: Applications/Multimedia
|
Group: Applications/Multimedia
|
||||||
License: GPL-3.0+
|
License: GPL-3.0+
|
||||||
URL: http://www.strawbs.org/
|
URL: http://www.strawbs.org/
|
||||||
@@ -21,7 +21,9 @@ BuildRequires: hicolor-icon-theme
|
|||||||
BuildRequires: make
|
BuildRequires: make
|
||||||
BuildRequires: git
|
BuildRequires: git
|
||||||
BuildRequires: pkgconfig
|
BuildRequires: pkgconfig
|
||||||
|
BuildRequires: gettext-tools
|
||||||
BuildRequires: update-desktop-files
|
BuildRequires: update-desktop-files
|
||||||
|
BuildRequires: cmake(Qt5LinguistTools)
|
||||||
BuildRequires: pkgconfig(glib-2.0)
|
BuildRequires: pkgconfig(glib-2.0)
|
||||||
BuildRequires: pkgconfig(gio-2.0)
|
BuildRequires: pkgconfig(gio-2.0)
|
||||||
BuildRequires: pkgconfig(gio-unix-2.0)
|
BuildRequires: pkgconfig(gio-unix-2.0)
|
||||||
@@ -57,7 +59,7 @@ BuildRequires: pkgconfig(libvlc)
|
|||||||
Requires: libQt5Sql5-sqlite
|
Requires: libQt5Sql5-sqlite
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Strawberry is a audio player and music collection organizer.
|
Strawberry is a music player and collection organizer.
|
||||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
@@ -70,7 +72,7 @@ Features:
|
|||||||
* Edit tags on music files
|
* Edit tags on music files
|
||||||
* Fetch tags from MusicBrainz
|
* Fetch tags from MusicBrainz
|
||||||
* Album cover art from Last.fm, Musicbrainz and Discogs
|
* Album cover art from Last.fm, Musicbrainz and Discogs
|
||||||
* Song lyrics from AudD and API Seeds
|
* Song lyrics from AudD
|
||||||
* Support for multiple backends
|
* Support for multiple backends
|
||||||
* Audio analyzer
|
* Audio analyzer
|
||||||
* Audio equalizer
|
* Audio equalizer
|
||||||
@@ -82,12 +84,15 @@ Features:
|
|||||||
%setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@
|
%setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@
|
||||||
|
|
||||||
%build
|
%build
|
||||||
%{cmake} .. -DUSE_INSTALL_PREFIX=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
%{cmake} .. -DUSE_INSTALL_PREFIX=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DENABLE_TRANSLATIONS=ON
|
||||||
make %{?_smp_mflags}
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
%install
|
%install
|
||||||
cd build
|
cd build
|
||||||
make install DESTDIR=$RPM_BUILD_ROOT
|
make install DESTDIR=$RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
%suse_update_desktop_file org.strawbs.strawberry Qt AudioVideo Audio Player
|
||||||
|
|
||||||
%if 0%{?suse_version} < 1500
|
%if 0%{?suse_version} < 1500
|
||||||
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
||||||
%endif
|
%endif
|
||||||
@@ -97,11 +102,11 @@ cd build
|
|||||||
make clean
|
make clean
|
||||||
|
|
||||||
%check
|
%check
|
||||||
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
|
desktop-file-validate %{buildroot}%{_datadir}/applications/org.strawbs.strawberry.desktop
|
||||||
%if 0%{?suse_version} >= 1500
|
%if 0%{?suse_version} >= 1500
|
||||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/strawberry.appdata.xml
|
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/org.strawbs.strawberry.appdata.xml
|
||||||
%else
|
%else
|
||||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry.appdata.xml
|
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/org.strawbs.strawberry.appdata.xml
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%files
|
%files
|
||||||
@@ -110,15 +115,15 @@ appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry
|
|||||||
%license COPYING
|
%license COPYING
|
||||||
%{_bindir}/strawberry
|
%{_bindir}/strawberry
|
||||||
%{_bindir}/strawberry-tagreader
|
%{_bindir}/strawberry-tagreader
|
||||||
%{_datadir}/applications/strawberry.desktop
|
%{_datadir}/applications/*.desktop
|
||||||
%{_datadir}/icons/hicolor/48x48/apps/strawberry.png
|
%{_datadir}/icons/hicolor/48x48/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
||||||
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
||||||
%if 0%{?suse_version} >= 1500
|
%if 0%{?suse_version} >= 1500
|
||||||
%{_datadir}/metainfo/strawberry.appdata.xml
|
%{_datadir}/metainfo/*.appdata.xml
|
||||||
%else
|
%else
|
||||||
%{_datadir}/appdata/strawberry.appdata.xml
|
%{_datadir}/appdata/*.appdata.xml
|
||||||
%endif
|
%endif
|
||||||
%{_mandir}/man1/%{name}.1%{?ext_man}
|
%{_mandir}/man1/%{name}.1%{?ext_man}
|
||||||
%{_mandir}/man1/%{name}-tagreader.1%{?ext_man}
|
%{_mandir}/man1/%{name}-tagreader.1%{?ext_man}
|
||||||
|
|||||||
24
dist/pacman/PKGBUILD.in
vendored
@@ -6,7 +6,7 @@ pkgdesc="A music player aimed at audio enthusiasts and music collectors"
|
|||||||
arch=(x86_64)
|
arch=(x86_64)
|
||||||
url="http://www.strawbs.org/"
|
url="http://www.strawbs.org/"
|
||||||
license=(GPL3)
|
license=(GPL3)
|
||||||
makedepends=(git cmake make gcc boost)
|
makedepends=(git cmake make gcc boost gettext qt5-tools)
|
||||||
depends=(
|
depends=(
|
||||||
desktop-file-utils
|
desktop-file-utils
|
||||||
hicolor-icon-theme
|
hicolor-icon-theme
|
||||||
@@ -40,30 +40,24 @@ optdepends=(
|
|||||||
)
|
)
|
||||||
provides=(strawberry)
|
provides=(strawberry)
|
||||||
conflicts=(strawberry)
|
conflicts=(strawberry)
|
||||||
source=("git+https://github.com/jonaski/strawberry.git")
|
source=("strawberry-@STRAWBERRY_VERSION_PACKAGE@.tar.xz")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
pkgver() {
|
|
||||||
cd "strawberry"
|
|
||||||
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare() {
|
prepare() {
|
||||||
cd "${srcdir}/strawberry"
|
mkdir -p build
|
||||||
install -d strawberry-build
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "${srcdir}/strawberry/strawberry-build"
|
cd build
|
||||||
cmake .. \
|
cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
-DUSE_SYSTEM_TAGLIB=ON \
|
-DUSE_SYSTEM_TAGLIB=ON \
|
||||||
-DENABLE_STREAM_DEEZER=ON \
|
-DENABLE_PHONON=ON \
|
||||||
-DENABLE_PHONON=ON
|
-DENABLE_TRANSLATIONS=ON
|
||||||
make
|
make -j$(nproc)
|
||||||
}
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
cd "${srcdir}/strawberry/strawberry-build"
|
cd build
|
||||||
make DESTDIR="${pkgdir}" install
|
make DESTDIR="${pkgdir}" install
|
||||||
}
|
}
|
||||||
|
|||||||
4
dist/scripts/maketarball.sh.in
vendored
@@ -26,6 +26,10 @@ tar -cJf $name-$version.tar.xz \
|
|||||||
--exclude="*.nsi" \
|
--exclude="*.nsi" \
|
||||||
--exclude="$root/CMakeLists.txt.user" \
|
--exclude="$root/CMakeLists.txt.user" \
|
||||||
--exclude="$root/build" \
|
--exclude="$root/build" \
|
||||||
|
--exclude="$root/scripts/maketarball.sh" \
|
||||||
--exclude="$root/dist/debian/changelog" \
|
--exclude="$root/dist/debian/changelog" \
|
||||||
--exclude="$root/dist/pacman/PKGBUILD" \
|
--exclude="$root/dist/pacman/PKGBUILD" \
|
||||||
|
--exclude="$root/dist/macos/create-dmg.sh" \
|
||||||
|
--exclude="$root/dist/macos/Info.plist" \
|
||||||
|
--exclude="$root/dist/windows/windres.rc" \
|
||||||
"$root"
|
"$root"
|
||||||
|
|||||||
260
dist/scripts/upload.sh
vendored
@@ -1,260 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set +x # Do not leak information
|
|
||||||
|
|
||||||
# Exit immediately if one of the files given as arguments is not there
|
|
||||||
# because we don't want to delete the existing release if we don't have
|
|
||||||
# the new files that should be uploaded
|
|
||||||
for file in "$@"
|
|
||||||
do
|
|
||||||
if [ ! -e "$file" ]
|
|
||||||
then echo "$file is missing, giving up." >&2; exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $# -eq 0 ]; then
|
|
||||||
echo "No artifacts to use for release, giving up."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v sha256sum >/dev/null 2>&1 ; then
|
|
||||||
shatool="sha256sum"
|
|
||||||
elif command -v shasum >/dev/null 2>&1 ; then
|
|
||||||
shatool="shasum -a 256" # macOS fallback
|
|
||||||
else
|
|
||||||
echo "Neither sha256sum nor shasum is available, cannot check hashes"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# The calling script (usually .travis.yml) can set a suffix to be used for
|
|
||||||
# the tag and release name. This way it is possible to have a release for
|
|
||||||
# the output of the CI/CD pipeline (marked as 'continuous') and also test
|
|
||||||
# builds for other branches.
|
|
||||||
# If this build was triggered by a tag, call the result a Release
|
|
||||||
if [ ! -z "$UPLOADTOOL_SUFFIX" ] ; then
|
|
||||||
if [ "$UPLOADTOOL_SUFFIX" = "$TRAVIS_TAG" ] ; then
|
|
||||||
RELEASE_NAME="$TRAVIS_TAG"
|
|
||||||
RELEASE_TITLE="Release build ($TRAVIS_TAG)"
|
|
||||||
is_prerelease="false"
|
|
||||||
else
|
|
||||||
RELEASE_NAME="continuous-$UPLOADTOOL_SUFFIX"
|
|
||||||
RELEASE_TITLE="Continuous build ($UPLOADTOOL_SUFFIX)"
|
|
||||||
is_prerelease="true"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ "$TRAVIS_TAG" != "" ]; then
|
|
||||||
RELEASE_NAME="$TRAVIS_TAG"
|
|
||||||
RELEASE_TITLE="Release build ($TRAVIS_TAG)"
|
|
||||||
is_prerelease="false"
|
|
||||||
else
|
|
||||||
RELEASE_NAME="continuous" # Do not use "latest" as it is reserved by GitHub
|
|
||||||
RELEASE_TITLE="Continuous build"
|
|
||||||
is_prerelease="true"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$ARTIFACTORY_BASE_URL" != "" ]; then
|
|
||||||
echo "ARTIFACTORY_BASE_URL set, trying to upload to artifactory"
|
|
||||||
|
|
||||||
if [ "$ARTIFACTORY_API_KEY" == "" ]; then
|
|
||||||
echo "Please set ARTIFACTORY_API_KEY"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
files="$@"
|
|
||||||
|
|
||||||
# artifactory doesn't support any kind of "artifact description", so we're uploading a text file containing the
|
|
||||||
# relevant details along with the other artifacts
|
|
||||||
tempdir=$(mktemp -d)
|
|
||||||
info_file="$tempdir"/build-info.txt
|
|
||||||
echo "Travis CI build log: https://travis-ci.com/$TRAVIS_REPO_SLUG/builds/$TRAVIS_BUILD_ID/" > "$info_file"
|
|
||||||
files+=("$info_file")
|
|
||||||
|
|
||||||
set +x
|
|
||||||
|
|
||||||
for file in ${files[@]}; do
|
|
||||||
url="${ARTIFACTORY_BASE_URL}/travis-${TRAVIS_BUILD_NUMBER}/"$(basename "$file")
|
|
||||||
md5sum=$(md5sum "$file" | cut -d' ' -f1)
|
|
||||||
sha1sum=$(sha1sum "$file" | cut -d' ' -f1)
|
|
||||||
sha256sum=$(sha256sum "$file" | cut -d' ' -f1)
|
|
||||||
echo "Uploading $file to $url"
|
|
||||||
hashsums=(-H "X-Checksum-Md5:$md5sum")
|
|
||||||
hashsums+=(-H "X-Checksum-Sha1:$sha1sum")
|
|
||||||
hashsums+=(-H "X-Checksum-Sha256:$sha256sum")
|
|
||||||
if ! curl -H 'X-JFrog-Art-Api:'"$ARTIFACTORY_API_KEY" "${hashsums[@]}" -T "$file" "$url"; then
|
|
||||||
echo "Failed to upload file, exiting"
|
|
||||||
rm -r "$tempdir"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
echo "MD5 checksum: $md5sum"
|
|
||||||
echo "SHA1 checksum: $sha1sum"
|
|
||||||
echo "SHA256 checksum: $sha256sum"
|
|
||||||
done
|
|
||||||
rm -r "$tempdir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Do not upload non-master branch builds
|
|
||||||
# if [ "$TRAVIS_TAG" != "$TRAVIS_BRANCH" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
|
||||||
if [ "$TRAVIS_EVENT_TYPE" == "pull_request" ] ; then
|
|
||||||
echo "Release uploading disabled for pull requests"
|
|
||||||
if [ "$ARTIFACTORY_BASE_URL" != "" ]; then
|
|
||||||
echo "Releases have already been uploaded to Artifactory, exiting"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
echo "Release uploading disabled for pull requests, uploading to transfer.sh instead"
|
|
||||||
rm -f ./uploaded-to
|
|
||||||
for FILE in "$@" ; do
|
|
||||||
BASENAME="$(basename "${FILE}")"
|
|
||||||
curl --upload-file $FILE "https://transfer.sh/$BASENAME" > ./one-upload
|
|
||||||
echo "$(cat ./one-upload)" # this way we get a newline
|
|
||||||
echo -n "$(cat ./one-upload)\\n" >> ./uploaded-to # this way we get a \n but no newline
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
# review_url="https://api.github.com/repos/${TRAVIS_REPO_SLUG}/pulls/${TRAVIS_PULL_REQUEST}/reviews"
|
|
||||||
# if [ -z $UPLOADTOOL_PR_BODY ] ; then
|
|
||||||
# body="Travis CI has created build artifacts for this PR here:"
|
|
||||||
# else
|
|
||||||
# body="$UPLOADTOOL_PR_BODY"
|
|
||||||
# fi
|
|
||||||
# body="$body\n$(cat ./uploaded-to)\nThe link(s) will expire 14 days from now."
|
|
||||||
# review_comment=$(curl -X POST \
|
|
||||||
# --header "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
# --data '{"commit_id": "'"$TRAVIS_COMMIT"'","body": "'"$body"'","event": "COMMENT"}' \
|
|
||||||
# $review_url)
|
|
||||||
# if echo $review_comment | grep -q "Bad credentials" 2>/dev/null ; then
|
|
||||||
# echo '"Bad credentials" response for --data {"commit_id": "'"$TRAVIS_COMMIT"'","body": "'"$body"'","event": "COMMENT"}'
|
|
||||||
# fi
|
|
||||||
$shatool "$@"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z "$TRAVIS_REPO_SLUG" ] ; then
|
|
||||||
# We are running on Travis CI
|
|
||||||
echo "Running on Travis CI"
|
|
||||||
echo "TRAVIS_COMMIT: $TRAVIS_COMMIT"
|
|
||||||
REPO_SLUG="$TRAVIS_REPO_SLUG"
|
|
||||||
if [ -z "$GITHUB_TOKEN" ] ; then
|
|
||||||
echo "\$GITHUB_TOKEN missing, please set it in the Travis CI settings of this project"
|
|
||||||
echo "You can get one from https://github.com/settings/tokens"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# We are not running on Travis CI
|
|
||||||
echo "Not running on Travis CI"
|
|
||||||
if [ -z "$REPO_SLUG" ] ; then
|
|
||||||
read -r -p "Repo Slug (GitHub and Travis CI username/reponame): " REPO_SLUG
|
|
||||||
fi
|
|
||||||
if [ -z "$GITHUB_TOKEN" ] ; then
|
|
||||||
read -r -s -p "Token (https://github.com/settings/tokens): " GITHUB_TOKEN
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
tag_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
|
|
||||||
tag_infos=$(curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${tag_url}")
|
|
||||||
echo "tag_infos: $tag_infos"
|
|
||||||
tag_sha=$(echo "$tag_infos" | grep '"sha":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "tag_sha: $tag_sha"
|
|
||||||
|
|
||||||
release_url="https://api.github.com/repos/$REPO_SLUG/releases/tags/$RELEASE_NAME"
|
|
||||||
echo "Getting the release ID..."
|
|
||||||
echo "release_url: $release_url"
|
|
||||||
release_infos=$(curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${release_url}")
|
|
||||||
echo "release_infos: $release_infos"
|
|
||||||
release_id=$(echo "$release_infos" | grep "\"id\":" | head -n 1 | tr -s " " | cut -f 3 -d" " | cut -f 1 -d ",")
|
|
||||||
echo "release ID: $release_id"
|
|
||||||
upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "upload_url: $upload_url"
|
|
||||||
release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "release_url: $release_url"
|
|
||||||
target_commit_sha=$(echo "$release_infos" | grep '"target_commitish":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "target_commit_sha: $target_commit_sha"
|
|
||||||
|
|
||||||
if [ "$TRAVIS_COMMIT" != "$target_commit_sha" ] ; then
|
|
||||||
|
|
||||||
echo "TRAVIS_COMMIT != target_commit_sha, hence deleting $RELEASE_NAME..."
|
|
||||||
|
|
||||||
if [ ! -z "$release_id" ]; then
|
|
||||||
delete_url="https://api.github.com/repos/$REPO_SLUG/releases/$release_id"
|
|
||||||
echo "Delete the release..."
|
|
||||||
echo "delete_url: $delete_url"
|
|
||||||
curl -XDELETE \
|
|
||||||
--header "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
"${delete_url}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# echo "Checking if release with the same name is still there..."
|
|
||||||
# echo "release_url: $release_url"
|
|
||||||
# curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
# "$release_url"
|
|
||||||
|
|
||||||
if [ "$is_prerelease" = "true" ] ; then
|
|
||||||
# if this is a continuous build tag, then delete the old tag
|
|
||||||
# in preparation for the new release
|
|
||||||
echo "Delete the tag..."
|
|
||||||
delete_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
|
|
||||||
echo "delete_url: $delete_url"
|
|
||||||
curl -XDELETE \
|
|
||||||
--header "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
"${delete_url}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Create release..."
|
|
||||||
|
|
||||||
if [ -z "$TRAVIS_BRANCH" ] ; then
|
|
||||||
TRAVIS_BRANCH="master"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z "$TRAVIS_JOB_ID" ] ; then
|
|
||||||
if [ -z "${UPLOADTOOL_BODY+x}" ] ; then
|
|
||||||
# TODO: The host could be travis-ci.org (legacy open source) or travis-ci.com (subscription or latest open source).
|
|
||||||
BODY="Travis CI build log: https://travis-ci.org/$REPO_SLUG/builds/$TRAVIS_BUILD_ID/"
|
|
||||||
else
|
|
||||||
BODY="$UPLOADTOOL_BODY"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
BODY="$UPLOADTOOL_BODY"
|
|
||||||
fi
|
|
||||||
|
|
||||||
release_infos=$(curl -H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
--data '{"tag_name": "'"$RELEASE_NAME"'","target_commitish": "'"$TRAVIS_COMMIT"'","name": "'"$RELEASE_TITLE"'","body": "'"$BODY"'","draft": false,"prerelease": '$is_prerelease'}' "https://api.github.com/repos/$REPO_SLUG/releases")
|
|
||||||
|
|
||||||
echo "$release_infos"
|
|
||||||
|
|
||||||
unset upload_url
|
|
||||||
upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "upload_url: $upload_url"
|
|
||||||
|
|
||||||
unset release_url
|
|
||||||
release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
|
|
||||||
echo "release_url: $release_url"
|
|
||||||
|
|
||||||
fi # if [ "$TRAVIS_COMMIT" != "$tag_sha" ]
|
|
||||||
|
|
||||||
if [ -z "$release_url" ] ; then
|
|
||||||
echo "Cannot figure out the release URL for $RELEASE_NAME"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Upload binaries to the release..."
|
|
||||||
|
|
||||||
for FILE in "$@" ; do
|
|
||||||
FULLNAME="${FILE}"
|
|
||||||
BASENAME="$(basename "${FILE}")"
|
|
||||||
curl -H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
-H "Accept: application/vnd.github.manifold-preview" \
|
|
||||||
-H "Content-Type: application/octet-stream" \
|
|
||||||
--data-binary @$FULLNAME \
|
|
||||||
"$upload_url?name=$BASENAME"
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
$shatool "$@"
|
|
||||||
|
|
||||||
if [ "$TRAVIS_COMMIT" != "$tag_sha" ] ; then
|
|
||||||
echo "Publish the release..."
|
|
||||||
|
|
||||||
release_infos=$(curl -H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
--data '{"draft": false}' "$release_url")
|
|
||||||
|
|
||||||
echo "$release_infos"
|
|
||||||
fi # if [ "$TRAVIS_COMMIT" != "$tag_sha" ]
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component>
|
<component>
|
||||||
<id>org.strawberry.strawberry</id>
|
<id>org.strawbs.strawberry</id>
|
||||||
<launchable type="desktop-id">strawberry.desktop</launchable>
|
<launchable type="desktop-id">strawberry.desktop</launchable>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-3.0+</project_license>
|
<project_license>GPL-3.0+</project_license>
|
||||||
@@ -9,13 +9,13 @@
|
|||||||
<binary>strawberry-tagreader</binary>
|
<binary>strawberry-tagreader</binary>
|
||||||
</provides>
|
</provides>
|
||||||
<name>Strawberry Music Player</name>
|
<name>Strawberry Music Player</name>
|
||||||
<summary>An audio player and music collection organizer</summary>
|
<summary>A music player and collection organizer</summary>
|
||||||
<url type="homepage">https://www.strawbs.org/</url>
|
<url type="homepage">https://www.strawbs.org/</url>
|
||||||
<url type="bugtracker">https://github.com/jonaski/strawberry/</url>
|
<url type="bugtracker">https://github.com/jonaski/strawberry/</url>
|
||||||
<translation type="qt">strawberry</translation>
|
<translation type="qt">strawberry</translation>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Strawberry is a audio player and music collection organizer.
|
Strawberry is a music player and music collection organizer.
|
||||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||||
</p>
|
</p>
|
||||||
<p>Features:</p>
|
<p>Features:</p>
|
||||||
@@ -29,12 +29,12 @@
|
|||||||
<li>Edit tags on music files</li>
|
<li>Edit tags on music files</li>
|
||||||
<li>Fetch tags from MusicBrainz</li>
|
<li>Fetch tags from MusicBrainz</li>
|
||||||
<li>Album cover art from Last.fm, Musicbrainz and Discogs</li>
|
<li>Album cover art from Last.fm, Musicbrainz and Discogs</li>
|
||||||
<li>Song lyrics from AudD and API Seeds</li>
|
<li>Song lyrics from AudD</li>
|
||||||
<li>Support for multiple backends</li>
|
<li>Support for multiple backends</li>
|
||||||
<li>Audio analyzer</li>
|
<li>Audio analyzer</li>
|
||||||
<li>Audio equalizer</li>
|
<li>Audio equalizer</li>
|
||||||
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
|
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
|
||||||
<li>Streaming support for Tidal and Deezer</li>
|
<li>Streaming support for Tidal</li>
|
||||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
13
dist/unix/org.strawbs.strawberry.desktop
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Strawberry
|
||||||
|
GenericName=Strawberry Music Player
|
||||||
|
Comment=Plays music
|
||||||
|
Exec=strawberry %U
|
||||||
|
TryExec=strawberry
|
||||||
|
Icon=strawberry
|
||||||
|
Terminal=false
|
||||||
|
Categories=AudioVideo;Player;Qt;Audio;
|
||||||
|
StartupNotify=false
|
||||||
|
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;
|
||||||
13
dist/unix/strawberry.desktop
vendored
@@ -1,13 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Type=Application
|
|
||||||
Name=Strawberry
|
|
||||||
GenericName=Strawberry Music Player
|
|
||||||
Comment=Plays music
|
|
||||||
Exec=strawberry %U
|
|
||||||
TryExec=strawberry
|
|
||||||
Icon=strawberry
|
|
||||||
Terminal=false
|
|
||||||
Categories=AudioVideo;Player;Qt;Audio;
|
|
||||||
StartupNotify=false
|
|
||||||
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/ogg;audio/vorbis;audio/vnd.rn-realaudio;audio/x-wav;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;audio/x-speex;video/x-ms-asf;
|
|
||||||
6
dist/windows/strawberry-debug-x64.nsi.in
vendored
@@ -137,7 +137,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libpcre-1.dll"
|
File "libpcre-1.dll"
|
||||||
File "libpcre2-16-0.dll"
|
File "libpcre2-16-0.dll"
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
File "libprotobuf-15.dll"
|
File "libprotobuf-18.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssl-1_1-x64.dll"
|
File "libssl-1_1-x64.dll"
|
||||||
@@ -162,7 +162,6 @@ Section "Strawberry" Strawberry
|
|||||||
File "libxml2-2.dll"
|
File "libxml2-2.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
File "libsoup-2.4-1.dll"
|
||||||
File "liblzma-5.dll"
|
File "liblzma-5.dll"
|
||||||
File "libdeezer.x64.dll"
|
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -378,7 +377,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libpcre-1.dll"
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
Delete "$INSTDIR\libprotobuf-18.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
||||||
@@ -403,7 +402,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libxml2-2.dll"
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
Delete "$INSTDIR\liblzma-5.dll"
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
Delete "$INSTDIR\libdeezer.x64.dll"
|
|
||||||
|
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|||||||
6
dist/windows/strawberry-debug-x86.nsi.in
vendored
@@ -137,7 +137,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libpcre-1.dll"
|
File "libpcre-1.dll"
|
||||||
File "libpcre2-16-0.dll"
|
File "libpcre2-16-0.dll"
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
File "libprotobuf-15.dll"
|
File "libprotobuf-18.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssl-1_1.dll"
|
File "libssl-1_1.dll"
|
||||||
@@ -162,7 +162,6 @@ Section "Strawberry" Strawberry
|
|||||||
File "libxml2-2.dll"
|
File "libxml2-2.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
File "libsoup-2.4-1.dll"
|
||||||
File "liblzma-5.dll"
|
File "liblzma-5.dll"
|
||||||
File "libdeezer.x86.dll"
|
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -378,7 +377,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libpcre-1.dll"
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
Delete "$INSTDIR\libprotobuf-18.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssl-1_1.dll"
|
Delete "$INSTDIR\libssl-1_1.dll"
|
||||||
@@ -403,7 +402,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libxml2-2.dll"
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
Delete "$INSTDIR\liblzma-5.dll"
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
Delete "$INSTDIR\libdeezer.x86.dll"
|
|
||||||
|
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|||||||
6
dist/windows/strawberry-x64.nsi.in
vendored
@@ -137,7 +137,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libpcre-1.dll"
|
File "libpcre-1.dll"
|
||||||
File "libpcre2-16-0.dll"
|
File "libpcre2-16-0.dll"
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
File "libprotobuf-15.dll"
|
File "libprotobuf-18.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssl-1_1-x64.dll"
|
File "libssl-1_1-x64.dll"
|
||||||
@@ -161,7 +161,6 @@ Section "Strawberry" Strawberry
|
|||||||
File "libxml2-2.dll"
|
File "libxml2-2.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
File "libsoup-2.4-1.dll"
|
||||||
File "liblzma-5.dll"
|
File "liblzma-5.dll"
|
||||||
File "libdeezer.x64.dll"
|
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -346,7 +345,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libpcre-1.dll"
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
Delete "$INSTDIR\libprotobuf-18.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
||||||
@@ -370,7 +369,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libxml2-2.dll"
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
Delete "$INSTDIR\liblzma-5.dll"
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
Delete "$INSTDIR\libdeezer.x64.dll"
|
|
||||||
|
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|||||||
6
dist/windows/strawberry-x86.nsi.in
vendored
@@ -137,7 +137,7 @@ Section "Strawberry" Strawberry
|
|||||||
File "libpcre-1.dll"
|
File "libpcre-1.dll"
|
||||||
File "libpcre2-16-0.dll"
|
File "libpcre2-16-0.dll"
|
||||||
File "libpng16-16.dll"
|
File "libpng16-16.dll"
|
||||||
File "libprotobuf-15.dll"
|
File "libprotobuf-18.dll"
|
||||||
File "libspeex-1.dll"
|
File "libspeex-1.dll"
|
||||||
File "libsqlite3-0.dll"
|
File "libsqlite3-0.dll"
|
||||||
File "libssl-1_1.dll"
|
File "libssl-1_1.dll"
|
||||||
@@ -161,7 +161,6 @@ Section "Strawberry" Strawberry
|
|||||||
File "libxml2-2.dll"
|
File "libxml2-2.dll"
|
||||||
File "libsoup-2.4-1.dll"
|
File "libsoup-2.4-1.dll"
|
||||||
File "liblzma-5.dll"
|
File "liblzma-5.dll"
|
||||||
File "libdeezer.x86.dll"
|
|
||||||
|
|
||||||
; Register Strawberry with Default Programs
|
; Register Strawberry with Default Programs
|
||||||
Var /GLOBAL AppIcon
|
Var /GLOBAL AppIcon
|
||||||
@@ -346,7 +345,7 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libpcre-1.dll"
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
Delete "$INSTDIR\libpcre2-16-0.dll"
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
Delete "$INSTDIR\libpng16-16.dll"
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
Delete "$INSTDIR\libprotobuf-18.dll"
|
||||||
Delete "$INSTDIR\libspeex-1.dll"
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
Delete "$INSTDIR\libssl-1_1.dll"
|
Delete "$INSTDIR\libssl-1_1.dll"
|
||||||
@@ -370,7 +369,6 @@ Section "Uninstall"
|
|||||||
Delete "$INSTDIR\libxml2-2.dll"
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
Delete "$INSTDIR\liblzma-5.dll"
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
Delete "$INSTDIR\libdeezer.x86.dll"
|
|
||||||
|
|
||||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|||||||
@@ -171,26 +171,14 @@ class CallbackClosure : public ClosureBase {
|
|||||||
} // namespace _detail
|
} // namespace _detail
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
_detail::ClosureBase *NewClosure(
|
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||||
QObject *sender,
|
return new _detail::Closure<Args...>(sender, signal, receiver, slot, args...);
|
||||||
const char *signal,
|
|
||||||
QObject *receiver,
|
|
||||||
const char *slot,
|
|
||||||
const Args&... args) {
|
|
||||||
return new _detail::Closure<Args...>(
|
|
||||||
sender, signal, receiver, slot, args...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QSharedPointer variant
|
// QSharedPointer variant
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
_detail::ClosureBase *NewClosure(
|
_detail::ClosureBase *NewClosure(QSharedPointer<T> sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||||
QSharedPointer<T> sender,
|
return new _detail::SharedClosure<T, Args...>(sender, signal, receiver, slot, args...);
|
||||||
const char *signal,
|
|
||||||
QObject *receiver,
|
|
||||||
const char *slot,
|
|
||||||
const Args&... args) {
|
|
||||||
return new _detail::SharedClosure<T, Args...>(
|
|
||||||
sender, signal, receiver, slot, args...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
||||||
@@ -201,20 +189,12 @@ _detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::funct
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
_detail::ClosureBase *NewClosure(
|
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, void (*callback)(Args...), const Args&... args) {
|
||||||
QObject *sender,
|
|
||||||
const char *signal,
|
|
||||||
void (*callback)(Args...),
|
|
||||||
const Args&... args) {
|
|
||||||
return NewClosure(sender, signal, std::bind(callback, args...));
|
return NewClosure(sender, signal, std::bind(callback, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename Unused, typename... Args>
|
template <typename T, typename Unused, typename... Args>
|
||||||
_detail::ClosureBase *NewClosure(
|
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, T *receiver, Unused (T::*callback)(Args...), const Args&... args) {
|
||||||
QObject *sender,
|
|
||||||
const char *signal,
|
|
||||||
T *receiver, Unused (T::*callback)(Args...),
|
|
||||||
const Args&... args) {
|
|
||||||
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
|
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,4 +229,3 @@ void DoAfter(std::function<void()> callback, std::chrono::duration<R, P> duratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // CLOSURE_H
|
#endif // CLOSURE_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
/* This file is part of Clementine.
|
/* This file is part of Strawberry.
|
||||||
Copyright 2016, John Maguire <john.maguire@gmail.com>
|
Copyright 2016, John Maguire <john.maguire@gmail.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Strawberry is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
Strawberry is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LAZY_H
|
#ifndef LAZY_H
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ class _MessageHandlerBase : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// device can be NULL, in which case you must call SetDevice before writing
|
// device can be nullptr, in which case you must call SetDevice before writing any messages.
|
||||||
// any messages.
|
|
||||||
_MessageHandlerBase(QIODevice *device, QObject *parent);
|
_MessageHandlerBase(QIODevice *device, QObject *parent);
|
||||||
|
|
||||||
void SetDevice(QIODevice *device);
|
void SetDevice(QIODevice *device);
|
||||||
@@ -176,4 +175,3 @@ void AbstractMessageHandler<MT>::AbortAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // MESSAGEHANDLER_H
|
#endif // MESSAGEHANDLER_H
|
||||||
|
|
||||||
|
|||||||
@@ -43,18 +43,17 @@ class _MessageReplyBase : public QObject {
|
|||||||
|
|
||||||
void Abort();
|
void Abort();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Finished(bool success);
|
void Finished(bool success);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool finished_;
|
bool finished_;
|
||||||
bool success_;
|
bool success_;
|
||||||
|
|
||||||
QSemaphore semaphore_;
|
QSemaphore semaphore_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A reply future class that is returned immediately for requests that will
|
// A reply future class that is returned immediately for requests that will occur in the background. Similar to QNetworkReply.
|
||||||
// occur in the background. Similar to QNetworkReply.
|
|
||||||
template <typename MessageType>
|
template <typename MessageType>
|
||||||
class MessageReply : public _MessageReplyBase {
|
class MessageReply : public _MessageReplyBase {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct Worker {
|
struct Worker {
|
||||||
Worker() : local_server_(NULL), local_socket_(NULL), process_(NULL), handler_(NULL) {}
|
Worker() : local_server_(nullptr), local_socket_(nullptr), process_(nullptr), handler_(nullptr) {}
|
||||||
|
|
||||||
QLocalServer *local_server_;
|
QLocalServer *local_server_;
|
||||||
QLocalSocket *local_socket_;
|
QLocalSocket *local_socket_;
|
||||||
@@ -120,14 +120,14 @@ private:
|
|||||||
return &(*it);
|
return &(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void DeleteQObjectPointerLater(T **p) {
|
void DeleteQObjectPointerLater(T **p) {
|
||||||
if (*p) {
|
if (*p) {
|
||||||
(*p)->deleteLater();
|
(*p)->deleteLater();
|
||||||
*p = NULL;
|
*p = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ private:
|
|||||||
// and sets the request's ID to the ID of the reply. Can be called from any thread
|
// and sets the request's ID to the ID of the reply. Can be called from any thread
|
||||||
ReplyType *NewReply(MessageType *message);
|
ReplyType *NewReply(MessageType *message);
|
||||||
|
|
||||||
// Returns the next handler, or NULL if there isn't one. Must be called from my thread.
|
// Returns the next handler, or nullptr if there isn't one. Must be called from my thread.
|
||||||
HandlerType *NextHandler() const;
|
HandlerType *NextHandler() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -300,7 +300,7 @@ void WorkerPool<HandlerType>::NewConnection() {
|
|||||||
// We only ever accept one connection per worker, so destroy the server now.
|
// We only ever accept one connection per worker, so destroy the server now.
|
||||||
worker->local_socket_->setParent(this);
|
worker->local_socket_->setParent(this);
|
||||||
worker->local_server_->deleteLater();
|
worker->local_server_->deleteLater();
|
||||||
worker->local_server_ = NULL;
|
worker->local_server_ = nullptr;
|
||||||
|
|
||||||
// Create the handler.
|
// Create the handler.
|
||||||
worker->handler_ = new HandlerType(worker->local_socket_, this);
|
worker->handler_ = new HandlerType(worker->local_socket_, this);
|
||||||
@@ -329,7 +329,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// On any other error we just restart the process.
|
// On any other error we just restart the process.
|
||||||
qLog(Debug) << "Worker" << worker << "failed with error" << error << "- restarting";
|
qLog(Debug) << "Worker" << worker << "failed with error" << error << "- restarting";
|
||||||
StartOneWorker(worker);
|
StartOneWorker(worker);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -386,14 +386,13 @@ HandlerType *WorkerPool<HandlerType>::NextHandler() const {
|
|||||||
for (int i = 0; i < workers_.count(); ++i) {
|
for (int i = 0; i < workers_.count(); ++i) {
|
||||||
const int worker_index = (next_worker_ + i) % workers_.count();
|
const int worker_index = (next_worker_ + i) % workers_.count();
|
||||||
|
|
||||||
if (workers_[worker_index].handler_ &&
|
if (workers_[worker_index].handler_ && !workers_[worker_index].handler_->is_device_closed()) {
|
||||||
!workers_[worker_index].handler_->is_device_closed()) {
|
|
||||||
next_worker_ = (worker_index + 1) % workers_.count();
|
next_worker_ = (worker_index + 1) % workers_.count();
|
||||||
return workers_[worker_index].handler_;
|
return workers_[worker_index].handler_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WORKERPOOL_H
|
#endif // WORKERPOOL_H
|
||||||
|
|||||||
@@ -92,11 +92,6 @@
|
|||||||
#include "fmpsparser.h"
|
#include "fmpsparser.h"
|
||||||
#include "core/timeconstants.h"
|
#include "core/timeconstants.h"
|
||||||
|
|
||||||
// Taglib added support for FLAC pictures in 1.7.0
|
|
||||||
#if (TAGLIB_MAJOR_VERSION > 1) || (TAGLIB_MAJOR_VERSION == 1 && TAGLIB_MINOR_VERSION >= 7)
|
|
||||||
# define TAGLIB_HAS_FLAC_PICTURELIST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class FileRefFactory {
|
class FileRefFactory {
|
||||||
public:
|
public:
|
||||||
virtual ~FileRefFactory() {}
|
virtual ~FileRefFactory() {}
|
||||||
@@ -106,11 +101,11 @@ class FileRefFactory {
|
|||||||
class TagLibFileRefFactory : public FileRefFactory {
|
class TagLibFileRefFactory : public FileRefFactory {
|
||||||
public:
|
public:
|
||||||
virtual TagLib::FileRef *GetFileRef(const QString &filename) {
|
virtual TagLib::FileRef *GetFileRef(const QString &filename) {
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
return new TagLib::FileRef(filename.toStdWString().c_str());
|
return new TagLib::FileRef(filename.toStdWString().c_str());
|
||||||
#else
|
#else
|
||||||
return new TagLib::FileRef(QFile::encodeName(filename).constData());
|
return new TagLib::FileRef(QFile::encodeName(filename).constData());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -127,18 +122,42 @@ TagLib::String QStringToTaglibString(const QString &s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Tags containing the year the album was originally released (in contrast to
|
// Tags containing the year the album was originally released (in contrast to other tags that contain the release year of the current edition)
|
||||||
// other tags that contain the release year of the current edition)
|
|
||||||
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
const char *kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
||||||
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
const char *kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
||||||
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
const char *kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TagReader::TagReader()
|
TagReader::TagReader() :
|
||||||
: factory_(new TagLibFileRefFactory),
|
factory_(new TagLibFileRefFactory),
|
||||||
network_(new QNetworkAccessManager),
|
network_(new QNetworkAccessManager),
|
||||||
kEmbeddedCover("(embedded)") {}
|
kEmbeddedCover("(embedded)") {}
|
||||||
|
|
||||||
|
pb::tagreader::SongMetadata_FileType TagReader::GuessFileType(TagLib::FileRef *fileref) const {
|
||||||
|
|
||||||
|
if (dynamic_cast<TagLib::RIFF::WAV::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAV;
|
||||||
|
if (dynamic_cast<TagLib::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_FLAC;
|
||||||
|
if (dynamic_cast<TagLib::WavPack::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAVPACK;
|
||||||
|
if (dynamic_cast<TagLib::Ogg::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGFLAC;
|
||||||
|
if (dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGVORBIS;
|
||||||
|
if (dynamic_cast<TagLib::Ogg::Opus::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGOPUS;
|
||||||
|
if (dynamic_cast<TagLib::Ogg::Speex::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGSPEEX;
|
||||||
|
if (dynamic_cast<TagLib::MPEG::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPEG;
|
||||||
|
if (dynamic_cast<TagLib::MP4::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MP4;
|
||||||
|
if (dynamic_cast<TagLib::ASF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_ASF;
|
||||||
|
if (dynamic_cast<TagLib::RIFF::AIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_AIFF;
|
||||||
|
if (dynamic_cast<TagLib::MPC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPC;
|
||||||
|
if (dynamic_cast<TagLib::TrueAudio::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_TRUEAUDIO;
|
||||||
|
if (dynamic_cast<TagLib::APE::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_APE;
|
||||||
|
#ifdef HAVE_TAGLIB_DSFFILE
|
||||||
|
if (dynamic_cast<TagLib::DSF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSF;
|
||||||
|
if (dynamic_cast<TagLib::DSDIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSDIFF;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return pb::tagreader::SongMetadata_FileType_UNKNOWN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const {
|
void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
@@ -186,29 +205,38 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
|||||||
// apart, so we keep specific behavior for some formats by adding another "else if" block below.
|
// apart, so we keep specific behavior for some formats by adding another "else if" block below.
|
||||||
if (TagLib::Ogg::XiphComment *tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
|
if (TagLib::Ogg::XiphComment *tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
|
||||||
ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song);
|
ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song);
|
||||||
#if TAGLIB_MAJOR_VERSION >= 1 && TAGLIB_MINOR_VERSION >= 11
|
if (!tag->pictureList().isEmpty()) {
|
||||||
if (!tag->pictureList().isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
song->set_art_automatic(kEmbeddedCover);
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
|
if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
|
||||||
|
|
||||||
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
||||||
|
|
||||||
if ( file->xiphComment() ) {
|
if (file->xiphComment()) {
|
||||||
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
|
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
|
||||||
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
|
|
||||||
if (!file->pictureList().isEmpty()) {
|
if (!file->pictureList().isEmpty()) {
|
||||||
song->set_art_automatic(kEmbeddedCover);
|
song->set_art_automatic(kEmbeddedCover);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
|
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
|
||||||
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
||||||
//if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
if (file->tag()) {
|
||||||
|
ParseAPETag(file->APETag()->itemListMap(), nullptr, &disc, &compilation, song);
|
||||||
|
}
|
||||||
|
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (TagLib::APE::File *file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
|
||||||
|
if (file->tag()) {
|
||||||
|
ParseAPETag(file->APETag()->itemListMap(), nullptr, &disc, &compilation, song);
|
||||||
|
}
|
||||||
|
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
||||||
|
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
|
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
|
||||||
@@ -217,7 +245,6 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
|||||||
const TagLib::ID3v2::FrameListMap &map = file->ID3v2Tag()->frameListMap();
|
const TagLib::ID3v2::FrameListMap &map = file->ID3v2Tag()->frameListMap();
|
||||||
|
|
||||||
if (!map["TPOS"].isEmpty()) disc = TStringToQString(map["TPOS"].front()->toString()).trimmed();
|
if (!map["TPOS"].isEmpty()) disc = TStringToQString(map["TPOS"].front()->toString()).trimmed();
|
||||||
//if (!map["TBPM"].isEmpty()) song->set_bpm(TStringToQString(map["TBPM"].front()->toString()).trimmed().toFloat());
|
|
||||||
if (!map["TCOM"].isEmpty()) Decode(map["TCOM"].front()->toString(), nullptr, song->mutable_composer());
|
if (!map["TCOM"].isEmpty()) Decode(map["TCOM"].front()->toString(), nullptr, song->mutable_composer());
|
||||||
|
|
||||||
// content group
|
// content group
|
||||||
@@ -330,8 +357,11 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::APE::File *file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
|
else if (TagLib::MPC::File* file = dynamic_cast<TagLib::MPC::File*>(fileref->file())) {
|
||||||
song->set_bitdepth(file->audioProperties()->bitsPerSample());
|
if (file->tag()) {
|
||||||
|
ParseAPETag(file->APETag()->itemListMap(), nullptr, &disc, &compilation, song);
|
||||||
|
}
|
||||||
|
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (tag) {
|
else if (tag) {
|
||||||
@@ -374,7 +404,6 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TagReader::Decode(const TagLib::String &tag, const QTextCodec *codec, std::string *output) {
|
void TagReader::Decode(const TagLib::String &tag, const QTextCodec *codec, std::string *output) {
|
||||||
|
|
||||||
QString tmp;
|
QString tmp;
|
||||||
@@ -403,6 +432,74 @@ void TagReader::Decode(const QString &tag, const QTextCodec *codec, std::string
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
|
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), codec, song->mutable_composer());
|
||||||
|
if (!map["PERFORMER"].isEmpty()) Decode(map["PERFORMER"].front(), codec, song->mutable_performer());
|
||||||
|
if (!map["CONTENT GROUP"].isEmpty()) Decode(map["CONTENT GROUP"].front(), codec, song->mutable_grouping());
|
||||||
|
|
||||||
|
if (!map["ALBUMARTIST"].isEmpty()) Decode(map["ALBUMARTIST"].front(), codec, song->mutable_albumartist());
|
||||||
|
else if (!map["ALBUM ARTIST"].isEmpty()) Decode(map["ALBUM ARTIST"].front(), codec, song->mutable_albumartist());
|
||||||
|
|
||||||
|
if (!map["ORIGINALDATE"].isEmpty()) song->set_originalyear(TStringToQString(map["ORIGINALDATE"].front()).left(4).toInt());
|
||||||
|
else if (!map["ORIGINALYEAR"].isEmpty()) song->set_originalyear(TStringToQString(map["ORIGINALYEAR"].front()).toInt());
|
||||||
|
|
||||||
|
if (!map["DISCNUMBER"].isEmpty()) *disc = TStringToQString( map["DISCNUMBER"].front() ).trimmed();
|
||||||
|
if (!map["COMPILATION"].isEmpty()) *compilation = TStringToQString( map["COMPILATION"].front() ).trimmed();
|
||||||
|
if (!map["COVERART"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
||||||
|
if (!map["METADATA_BLOCK_PICTURE"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
||||||
|
|
||||||
|
if (!map["FMPS_PLAYCOUNT"].isEmpty() && song->playcount() <= 0) song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat());
|
||||||
|
|
||||||
|
if (!map["LYRICS"].isEmpty()) Decode(map["LYRICS"].front(), codec, song->mutable_lyrics());
|
||||||
|
else if (!map["UNSYNCEDLYRICS"].isEmpty()) Decode(map["UNSYNCEDLYRICS"].front(), codec, song->mutable_lyrics());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagReader::ParseAPETag(const TagLib::APE::ItemListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
|
TagLib::APE::ItemListMap::ConstIterator it = map.find("ALBUM ARTIST");
|
||||||
|
if (it != map.end()) {
|
||||||
|
TagLib::StringList album_artists = it->second.toStringList();
|
||||||
|
if (!album_artists.isEmpty()) {
|
||||||
|
Decode(album_artists.front(), nullptr, song->mutable_albumartist());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.find("COVER ART (FRONT)") != map.end()) song->set_art_automatic(kEmbeddedCover);
|
||||||
|
if (map.contains("COMPILATION")) {
|
||||||
|
*compilation = TStringToQString(TagLib::String::number(map["COMPILATION"].toString().toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("DISC")) {
|
||||||
|
*disc = TStringToQString(TagLib::String::number(map["DISC"].toString().toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("PERFORMER")) {
|
||||||
|
Decode(map["PERFORMER"].toStringList().toString(", "), nullptr, song->mutable_performer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("COMPOSER")) {
|
||||||
|
Decode(map["COMPOSER"].toStringList().toString(", "), nullptr, song->mutable_composer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("GROUPING")) {
|
||||||
|
Decode(map["GROUPING"].toStringList().toString(" "), nullptr, song->mutable_grouping());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("LYRICS")) {
|
||||||
|
Decode(map["LYRICS"].toString(), nullptr, song->mutable_lyrics());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.contains("FMPS_PLAYCOUNT")) {
|
||||||
|
int playcount = TStringToQString(map["FMPS_PLAYCOUNT"].toString()).toFloat();
|
||||||
|
if (song->playcount() <= 0 && playcount > 0) {
|
||||||
|
song->set_playcount(playcount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const {
|
void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const {
|
||||||
|
|
||||||
qLog(Debug) << "Parsing FMPSFrame" << name << ", " << value;
|
qLog(Debug) << "Parsing FMPSFrame" << name << ", " << value;
|
||||||
@@ -430,38 +527,6 @@ void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::ta
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const {
|
|
||||||
|
|
||||||
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), codec, song->mutable_composer());
|
|
||||||
if (!map["PERFORMER"].isEmpty()) Decode(map["PERFORMER"].front(), codec, song->mutable_performer());
|
|
||||||
if (!map["CONTENT GROUP"].isEmpty()) Decode(map["CONTENT GROUP"].front(), codec, song->mutable_grouping());
|
|
||||||
|
|
||||||
if (!map["ALBUMARTIST"].isEmpty()) {
|
|
||||||
Decode(map["ALBUMARTIST"].front(), codec, song->mutable_albumartist());
|
|
||||||
}
|
|
||||||
else if (!map["ALBUM ARTIST"].isEmpty()) {
|
|
||||||
Decode(map["ALBUM ARTIST"].front(), codec, song->mutable_albumartist());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!map["ORIGINALDATE"].isEmpty())
|
|
||||||
song->set_originalyear(TStringToQString(map["ORIGINALDATE"].front()).left(4).toInt());
|
|
||||||
else if (!map["ORIGINALYEAR"].isEmpty())
|
|
||||||
song->set_originalyear(TStringToQString(map["ORIGINALYEAR"].front()).toInt());
|
|
||||||
|
|
||||||
if (!map["DISCNUMBER"].isEmpty()) *disc = TStringToQString( map["DISCNUMBER"].front() ).trimmed();
|
|
||||||
if (!map["COMPILATION"].isEmpty()) *compilation = TStringToQString( map["COMPILATION"].front() ).trimmed();
|
|
||||||
if (!map["COVERART"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
|
||||||
if (!map["METADATA_BLOCK_PICTURE"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
|
|
||||||
|
|
||||||
if (!map["FMPS_PLAYCOUNT"].isEmpty() && song->playcount() <= 0) song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat());
|
|
||||||
|
|
||||||
if (!map["LYRICS"].isEmpty())
|
|
||||||
Decode(map["LYRICS"].front(), codec, song->mutable_lyrics());
|
|
||||||
else if (!map["UNSYNCEDLYRICS"].isEmpty())
|
|
||||||
Decode(map["UNSYNCEDLYRICS"].front(), codec, song->mutable_lyrics());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const {
|
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const {
|
||||||
|
|
||||||
vorbis_comments->addField("COMPOSER", StdStringToTaglibString(song.composer()), true);
|
vorbis_comments->addField("COMPOSER", StdStringToTaglibString(song.composer()), true);
|
||||||
@@ -480,31 +545,6 @@ void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, con
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pb::tagreader::SongMetadata_FileType TagReader::GuessFileType(TagLib::FileRef *fileref) const {
|
|
||||||
|
|
||||||
if (dynamic_cast<TagLib::RIFF::WAV::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAV;
|
|
||||||
if (dynamic_cast<TagLib::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_FLAC;
|
|
||||||
if (dynamic_cast<TagLib::WavPack::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAVPACK;
|
|
||||||
if (dynamic_cast<TagLib::Ogg::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGFLAC;
|
|
||||||
if (dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGVORBIS;
|
|
||||||
if (dynamic_cast<TagLib::Ogg::Opus::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGOPUS;
|
|
||||||
if (dynamic_cast<TagLib::Ogg::Speex::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGSPEEX;
|
|
||||||
if (dynamic_cast<TagLib::MPEG::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPEG;
|
|
||||||
if (dynamic_cast<TagLib::MP4::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MP4;
|
|
||||||
if (dynamic_cast<TagLib::ASF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_ASF;
|
|
||||||
if (dynamic_cast<TagLib::RIFF::AIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_AIFF;
|
|
||||||
if (dynamic_cast<TagLib::MPC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPC;
|
|
||||||
if (dynamic_cast<TagLib::TrueAudio::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_TRUEAUDIO;
|
|
||||||
if (dynamic_cast<TagLib::APE::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_APE;
|
|
||||||
#ifdef HAVE_TAGLIB_DSFFILE
|
|
||||||
if (dynamic_cast<TagLib::DSF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSF;
|
|
||||||
if (dynamic_cast<TagLib::DSDIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSDIFF;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return pb::tagreader::SongMetadata_FileType_UNKNOWN;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const {
|
bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const {
|
||||||
|
|
||||||
if (filename.isNull() || filename.isEmpty()) return false;
|
if (filename.isNull() || filename.isEmpty()) return false;
|
||||||
@@ -524,17 +564,25 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
|
|||||||
TagLib::Ogg::XiphComment *tag = file->xiphComment();
|
TagLib::Ogg::XiphComment *tag = file->xiphComment();
|
||||||
SetVorbisComments(tag, song);
|
SetVorbisComments(tag, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
|
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
|
||||||
TagLib::APE::Tag *tag = file->APETag(true);
|
TagLib::APE::Tag *tag = file->APETag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
tag->setArtist(StdStringToTaglibString(song.artist()));
|
SaveAPETag(tag, song);
|
||||||
tag->setAlbum(StdStringToTaglibString(song.album()));
|
|
||||||
tag->setTitle(StdStringToTaglibString(song.title()));
|
|
||||||
tag->setGenre(StdStringToTaglibString(song.genre()));
|
|
||||||
tag->setComment(StdStringToTaglibString(song.comment()));
|
|
||||||
tag->setYear(song.year());
|
|
||||||
tag->setTrack(song.track());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (TagLib::APE::File *file = dynamic_cast<TagLib::APE::File*>(fileref->file())) {
|
||||||
|
TagLib::APE::Tag *tag = file->APETag(true);
|
||||||
|
if (!tag) return false;
|
||||||
|
SaveAPETag(tag, song);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (TagLib::MPC::File *file = dynamic_cast<TagLib::MPC::File*>(fileref->file())) {
|
||||||
|
TagLib::APE::Tag *tag = file->APETag(true);
|
||||||
|
if (!tag) return false;
|
||||||
|
SaveAPETag(tag, song);
|
||||||
|
}
|
||||||
|
|
||||||
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
|
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
|
||||||
TagLib::ID3v2::Tag *tag = file->ID3v2Tag(true);
|
TagLib::ID3v2::Tag *tag = file->ID3v2Tag(true);
|
||||||
if (!tag) return false;
|
if (!tag) return false;
|
||||||
@@ -547,6 +595,7 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
|
|||||||
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
|
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
|
||||||
SetUnsyncLyricsFrame(song.lyrics(), tag);
|
SetUnsyncLyricsFrame(song.lyrics(), tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
|
else if (TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
|
||||||
TagLib::MP4::Tag *tag = file->tag();
|
TagLib::MP4::Tag *tag = file->tag();
|
||||||
tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0);
|
tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0);
|
||||||
@@ -563,17 +612,28 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ret = fileref->save();
|
bool ret = fileref->save();
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// Linux: inotify doesn't seem to notice the change to the file unless we
|
// Linux: inotify doesn't seem to notice the change to the file unless we change the timestamps as well. (this is what touch does)
|
||||||
// change the timestamps as well. (this is what touch does)
|
|
||||||
utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0);
|
utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0);
|
||||||
}
|
}
|
||||||
#endif // Q_OS_LINUX
|
#endif // Q_OS_LINUX
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagReader::SaveAPETag(TagLib::APE::Tag *tag, const pb::tagreader::SongMetadata &song) const {
|
||||||
|
|
||||||
|
tag->setItem("album artist", TagLib::APE::Item("album artist", TagLib::StringList(song.albumartist().c_str())));
|
||||||
|
tag->setItem("disc", TagLib::APE::Item("disc", TagLib::String::number(song.disc() <= 0 - 1 ? 0 : song.disc())));
|
||||||
|
tag->setItem("composer", TagLib::APE::Item("composer", TagLib::StringList(song.composer().c_str())));
|
||||||
|
tag->setItem("grouping", TagLib::APE::Item("grouping", TagLib::StringList(song.grouping().c_str())));
|
||||||
|
tag->setItem("performer", TagLib::APE::Item("performer", TagLib::StringList(song.performer().c_str())));
|
||||||
|
tag->setItem("lyrics", TagLib::APE::Item("lyrics", TagLib::String(song.lyrics())));
|
||||||
|
tag->setItem("compilation", TagLib::APE::Item("compilation", TagLib::StringList(song.compilation() ? "1" : "0")));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void TagReader::SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const {
|
void TagReader::SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const {
|
||||||
|
|
||||||
const QByteArray descr_utf8(description.toUtf8());
|
const QByteArray descr_utf8(description.toUtf8());
|
||||||
@@ -659,7 +719,6 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
|
|||||||
|
|
||||||
if (ref.isNull() || !ref.file()) return QByteArray();
|
if (ref.isNull() || !ref.file()) return QByteArray();
|
||||||
|
|
||||||
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
|
|
||||||
// FLAC
|
// FLAC
|
||||||
TagLib::FLAC::File *flac_file = dynamic_cast<TagLib::FLAC::File*>(ref.file());
|
TagLib::FLAC::File *flac_file = dynamic_cast<TagLib::FLAC::File*>(ref.file());
|
||||||
if (flac_file && flac_file->xiphComment()) {
|
if (flac_file && flac_file->xiphComment()) {
|
||||||
@@ -674,32 +733,33 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
|
|||||||
return QByteArray(picture->data().data(), picture->data().size());
|
return QByteArray(picture->data().data(), picture->data().size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// WavPack
|
||||||
|
|
||||||
|
TagLib::WavPack::File *wavpack_file = dynamic_cast<TagLib::WavPack::File*>(ref.file());
|
||||||
|
if (wavpack_file) {
|
||||||
|
return LoadEmbeddedAPEArt(wavpack_file->APETag()->itemListMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// APE
|
||||||
|
|
||||||
|
TagLib::APE::File *ape_file = dynamic_cast<TagLib::APE::File*>(ref.file());
|
||||||
|
if (ape_file) {
|
||||||
|
return LoadEmbeddedAPEArt(ape_file->APETag()->itemListMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// MPC
|
||||||
|
|
||||||
|
TagLib::MPC::File *mpc_file = dynamic_cast<TagLib::MPC::File*>(ref.file());
|
||||||
|
if (mpc_file) {
|
||||||
|
return LoadEmbeddedAPEArt(mpc_file->APETag()->itemListMap());
|
||||||
|
}
|
||||||
|
|
||||||
// Ogg Vorbis / Speex
|
// Ogg Vorbis / Speex
|
||||||
TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(ref.file()->tag());
|
TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(ref.file()->tag());
|
||||||
if (xiph_comment) {
|
if (xiph_comment) {
|
||||||
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
|
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
|
||||||
|
|
||||||
#if TAGLIB_MAJOR_VERSION <= 1 && TAGLIB_MINOR_VERSION < 11
|
|
||||||
// Other than the below mentioned non-standard COVERART, METADATA_BLOCK_PICTURE is the proposed tag for cover pictures.
|
|
||||||
// (see http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE)
|
|
||||||
if (map.contains("METADATA_BLOCK_PICTURE")) {
|
|
||||||
TagLib::StringList pict_list = map["METADATA_BLOCK_PICTURE"];
|
|
||||||
for (std::list<TagLib::String>::iterator it = pict_list.begin(); it != pict_list.end(); ++it) {
|
|
||||||
QByteArray data(QByteArray::fromBase64(it->toCString()));
|
|
||||||
TagLib::ByteVector tdata(data.data(), data.size());
|
|
||||||
TagLib::FLAC::Picture p(tdata);
|
|
||||||
if (p.type() == TagLib::FLAC::Picture::FrontCover)
|
|
||||||
return QByteArray(p.data().data(), p.data().size());
|
|
||||||
}
|
|
||||||
// If there was no specific front cover, just take the first picture
|
|
||||||
QByteArray data(QByteArray::fromBase64(map["METADATA_BLOCK_PICTURE"].front().toCString()));
|
|
||||||
TagLib::ByteVector tdata(data.data(), data.size());
|
|
||||||
TagLib::FLAC::Picture p(tdata);
|
|
||||||
return QByteArray(p.data().data(), p.data().size());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
TagLib::List<TagLib::FLAC::Picture*> pics = xiph_comment->pictureList();
|
TagLib::List<TagLib::FLAC::Picture*> pics = xiph_comment->pictureList();
|
||||||
if (!pics.isEmpty()) {
|
if (!pics.isEmpty()) {
|
||||||
for (auto p : pics) {
|
for (auto p : pics) {
|
||||||
@@ -712,7 +772,6 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
|
|||||||
|
|
||||||
return QByteArray(picture->data().data(), picture->data().size());
|
return QByteArray(picture->data().data(), picture->data().size());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Ogg lacks a definitive standard for embedding cover art, but it seems
|
// Ogg lacks a definitive standard for embedding cover art, but it seems
|
||||||
// b64 encoding a field called COVERART is the general convention
|
// b64 encoding a field called COVERART is the general convention
|
||||||
@@ -754,6 +813,24 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray TagReader::LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const {
|
||||||
|
|
||||||
|
QByteArray ret;
|
||||||
|
|
||||||
|
TagLib::APE::ItemListMap::ConstIterator it = map.find("COVER ART (FRONT)");
|
||||||
|
if (it != map.end()) {
|
||||||
|
TagLib::ByteVector data = it->second.binaryData();
|
||||||
|
|
||||||
|
int pos = data.find('\0') + 1;
|
||||||
|
if ((pos > 0) && (pos < data.size())) {
|
||||||
|
ret = QByteArray(data.data() + pos, data.size() - pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void TagReader::SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const {
|
void TagReader::SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const {
|
||||||
|
|
||||||
TagLib::ByteVector id_vector("USLT");
|
TagLib::ByteVector id_vector("USLT");
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
|
|
||||||
#include <taglib/xiphcomment.h>
|
#include <taglib/xiphcomment.h>
|
||||||
|
#include <taglib/apetag.h>
|
||||||
|
#include <taglib/apefile.h>
|
||||||
|
|
||||||
#include "tagreadermessages.pb.h"
|
#include "tagreadermessages.pb.h"
|
||||||
|
|
||||||
@@ -52,20 +54,24 @@ class TagReader {
|
|||||||
public:
|
public:
|
||||||
TagReader();
|
TagReader();
|
||||||
|
|
||||||
|
pb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
|
||||||
|
|
||||||
void ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const;
|
void ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const;
|
||||||
bool SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const;
|
bool SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const;
|
||||||
|
|
||||||
bool IsMediaFile(const QString &filename) const;
|
bool IsMediaFile(const QString &filename) const;
|
||||||
QByteArray LoadEmbeddedArt(const QString &filename) const;
|
QByteArray LoadEmbeddedArt(const QString &filename) const;
|
||||||
|
QByteArray LoadEmbeddedAPEArt(const TagLib::APE::ItemListMap &map) const;
|
||||||
|
|
||||||
static void Decode(const TagLib::String& tag, const QTextCodec *codec, std::string *output);
|
static void Decode(const TagLib::String& tag, const QTextCodec *codec, std::string *output);
|
||||||
static void Decode(const QString &tag, const QTextCodec *codec, std::string *output);
|
static void Decode(const QString &tag, const QTextCodec *codec, std::string *output);
|
||||||
|
|
||||||
void ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const;
|
|
||||||
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const;
|
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const;
|
||||||
void SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const;
|
void ParseAPETag(const TagLib::APE::ItemListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const;
|
||||||
|
void ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const;
|
||||||
|
|
||||||
pb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
|
void SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const;
|
||||||
|
void SaveAPETag(TagLib::APE::Tag *tag, const pb::tagreader::SongMetadata &song) const;
|
||||||
|
|
||||||
void SetUserTextFrame(const QString &description, const QString &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 SetUserTextFrame(const std::string &description, const std::string& value, TagLib::ID3v2::Tag *tag) const;
|
||||||
@@ -74,7 +80,7 @@ class TagReader {
|
|||||||
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
|
||||||
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
|
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
FileRefFactory *factory_;
|
FileRefFactory *factory_;
|
||||||
QNetworkAccessManager *network_;
|
QNetworkAccessManager *network_;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
class TagReaderWorker : public AbstractMessageHandler<pb::tagreader::Message> {
|
class TagReaderWorker : public AbstractMessageHandler<pb::tagreader::Message> {
|
||||||
public:
|
public:
|
||||||
TagReaderWorker(QIODevice *socket, QObject *parent = NULL);
|
TagReaderWorker(QIODevice *socket, QObject *parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void MessageArrived(const pb::tagreader::Message &message);
|
void MessageArrived(const pb::tagreader::Message &message);
|
||||||
|
|||||||
117
snap/snapcraft.yaml
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
name: strawberry
|
||||||
|
version: '0.5.2+git'
|
||||||
|
summary: music player and collection organizer
|
||||||
|
description: |
|
||||||
|
Strawberry is a music player and collection organizer.
|
||||||
|
It is a fork of Clementine released in 2018 aimed at music collectors,
|
||||||
|
audio enthusiasts and audiophiles
|
||||||
|
|
||||||
|
grade: stable
|
||||||
|
confinement: strict
|
||||||
|
|
||||||
|
parts:
|
||||||
|
strawberry:
|
||||||
|
plugin: cmake
|
||||||
|
source-type: git
|
||||||
|
source: https://github.com/jonaski/strawberry
|
||||||
|
after: [desktop-qt5]
|
||||||
|
|
||||||
|
build-packages:
|
||||||
|
- cmake
|
||||||
|
- make
|
||||||
|
- gcc
|
||||||
|
- g++
|
||||||
|
- protobuf-compiler
|
||||||
|
- libglib2.0-dev
|
||||||
|
- libdbus-1-dev
|
||||||
|
- libprotobuf-dev
|
||||||
|
- libboost-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- libasound2-dev
|
||||||
|
- libpulse-dev
|
||||||
|
- libtag1-dev
|
||||||
|
- qtbase5-dev
|
||||||
|
- qtbase5-dev-tools
|
||||||
|
- qtbase5-private-dev
|
||||||
|
- libqt5x11extras5-dev
|
||||||
|
- libgstreamer1.0-dev
|
||||||
|
- libgstreamer-plugins-base1.0-dev
|
||||||
|
- libxine2-dev
|
||||||
|
- libvlc-dev
|
||||||
|
- libcdio-dev
|
||||||
|
- libgpod-dev
|
||||||
|
- libimobiledevice-dev
|
||||||
|
- libmtp-dev
|
||||||
|
- libplist-dev
|
||||||
|
- libusbmuxd-dev
|
||||||
|
- libchromaprint-dev
|
||||||
|
|
||||||
|
stage-packages:
|
||||||
|
- libstdc++6
|
||||||
|
- libgcc1
|
||||||
|
- libprotobuf9v5
|
||||||
|
- libpcre16-3
|
||||||
|
- libqt5core5a
|
||||||
|
- libqt5gui5
|
||||||
|
- libqt5widgets5
|
||||||
|
- libqt5concurrent5
|
||||||
|
- libqt5network5
|
||||||
|
- libqt5dbus5
|
||||||
|
- libqt5sql5
|
||||||
|
- libqt5x11extras5
|
||||||
|
- libqt5sql5-sqlite
|
||||||
|
- libsqlite3-0
|
||||||
|
- libgpm2
|
||||||
|
- libasound2
|
||||||
|
- libpulse0
|
||||||
|
- libcdio13
|
||||||
|
- libgpod4
|
||||||
|
- libmtp9
|
||||||
|
- libimobiledevice6
|
||||||
|
- libplist3
|
||||||
|
- libusbmuxd4
|
||||||
|
- libxine2
|
||||||
|
- libvlc5
|
||||||
|
- libvlccore8
|
||||||
|
- libtag1v5
|
||||||
|
- libchromaprint0
|
||||||
|
- zlib1g
|
||||||
|
- libx11-6
|
||||||
|
- libdb5.3
|
||||||
|
- libgstreamer1.0-0
|
||||||
|
- libgstreamer-plugins-base1.0-0
|
||||||
|
- gstreamer1.0-alsa
|
||||||
|
- gstreamer1.0-pulseaudio
|
||||||
|
- gstreamer1.0-plugins-base
|
||||||
|
- gstreamer1.0-plugins-good
|
||||||
|
- gstreamer1.0-plugins-bad
|
||||||
|
- gstreamer1.0-plugins-ugly
|
||||||
|
- gstreamer1.0-libav
|
||||||
|
|
||||||
|
apps:
|
||||||
|
strawberry:
|
||||||
|
command: desktop-launch $SNAP/bin/strawberry
|
||||||
|
desktop: share/applications/org.strawbs.strawberry.desktop
|
||||||
|
environment:
|
||||||
|
LD_LIBRARY_PATH: $LD_LIBRARY_PATH:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio
|
||||||
|
plugs:
|
||||||
|
- system-observe
|
||||||
|
- system-trace
|
||||||
|
- home
|
||||||
|
- dbus
|
||||||
|
- mpris
|
||||||
|
- udisks2
|
||||||
|
- network
|
||||||
|
- network-bind
|
||||||
|
- desktop
|
||||||
|
- desktop-legacy
|
||||||
|
- x11
|
||||||
|
- wayland
|
||||||
|
- alsa
|
||||||
|
- pulseaudio
|
||||||
|
- removable-media
|
||||||
|
- optical-drive
|
||||||
|
- raw-usb
|
||||||
|
- media-hub
|
||||||
|
- screen-inhibit-control
|
||||||
|
- unity7
|
||||||
@@ -26,6 +26,10 @@ if(BUILD_WERROR)
|
|||||||
endif (LINUX)
|
endif (LINUX)
|
||||||
endif(BUILD_WERROR)
|
endif(BUILD_WERROR)
|
||||||
|
|
||||||
|
if(HAVE_TRANSLATIONS)
|
||||||
|
include(../cmake/Translations.cmake)
|
||||||
|
endif(HAVE_TRANSLATIONS)
|
||||||
|
|
||||||
# Set up definitions and paths
|
# Set up definitions and paths
|
||||||
|
|
||||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
@@ -60,14 +64,6 @@ if(HAVE_PHONON)
|
|||||||
include_directories(${PHONON_INCLUDE_DIRS})
|
include_directories(${PHONON_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_LIBDEEZER)
|
|
||||||
include_directories(${DEEZER_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_LIBDZMEDIA)
|
|
||||||
include_directories(${DZMEDIA_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
link_directories(${TAGLIB_LIBRARY_DIRS})
|
link_directories(${TAGLIB_LIBRARY_DIRS})
|
||||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||||
|
|
||||||
@@ -125,6 +121,8 @@ set(SOURCES
|
|||||||
analyzer/analyzerbase.cpp
|
analyzer/analyzerbase.cpp
|
||||||
analyzer/analyzercontainer.cpp
|
analyzer/analyzercontainer.cpp
|
||||||
analyzer/blockanalyzer.cpp
|
analyzer/blockanalyzer.cpp
|
||||||
|
analyzer/boomanalyzer.cpp
|
||||||
|
analyzer/rainbowanalyzer.cpp
|
||||||
|
|
||||||
equalizer/equalizer.cpp
|
equalizer/equalizer.cpp
|
||||||
equalizer/equalizerslider.cpp
|
equalizer/equalizerslider.cpp
|
||||||
@@ -206,7 +204,6 @@ set(SOURCES
|
|||||||
lyrics/lyricsfetcher.cpp
|
lyrics/lyricsfetcher.cpp
|
||||||
lyrics/lyricsfetchersearch.cpp
|
lyrics/lyricsfetchersearch.cpp
|
||||||
lyrics/auddlyricsprovider.cpp
|
lyrics/auddlyricsprovider.cpp
|
||||||
lyrics/apiseedslyricsprovider.cpp
|
|
||||||
|
|
||||||
settings/settingsdialog.cpp
|
settings/settingsdialog.cpp
|
||||||
settings/settingspage.cpp
|
settings/settingspage.cpp
|
||||||
@@ -242,7 +239,7 @@ set(SOURCES
|
|||||||
widgets/osd.cpp
|
widgets/osd.cpp
|
||||||
widgets/osdpretty.cpp
|
widgets/osdpretty.cpp
|
||||||
widgets/renametablineedit.cpp
|
widgets/renametablineedit.cpp
|
||||||
widgets/sliderwidget.cpp
|
widgets/volumeslider.cpp
|
||||||
widgets/stickyslider.cpp
|
widgets/stickyslider.cpp
|
||||||
widgets/stretchheaderview.cpp
|
widgets/stretchheaderview.cpp
|
||||||
widgets/stylehelper.cpp
|
widgets/stylehelper.cpp
|
||||||
@@ -307,6 +304,8 @@ set(HEADERS
|
|||||||
analyzer/analyzerbase.h
|
analyzer/analyzerbase.h
|
||||||
analyzer/analyzercontainer.h
|
analyzer/analyzercontainer.h
|
||||||
analyzer/blockanalyzer.h
|
analyzer/blockanalyzer.h
|
||||||
|
analyzer/boomanalyzer.h
|
||||||
|
analyzer/rainbowanalyzer.h
|
||||||
|
|
||||||
equalizer/equalizer.h
|
equalizer/equalizer.h
|
||||||
equalizer/equalizerslider.h
|
equalizer/equalizerslider.h
|
||||||
@@ -380,7 +379,6 @@ set(HEADERS
|
|||||||
lyrics/lyricsfetcher.h
|
lyrics/lyricsfetcher.h
|
||||||
lyrics/lyricsfetchersearch.h
|
lyrics/lyricsfetchersearch.h
|
||||||
lyrics/auddlyricsprovider.h
|
lyrics/auddlyricsprovider.h
|
||||||
lyrics/apiseedslyricsprovider.h
|
|
||||||
|
|
||||||
settings/settingsdialog.h
|
settings/settingsdialog.h
|
||||||
settings/settingspage.h
|
settings/settingspage.h
|
||||||
@@ -415,7 +413,7 @@ set(HEADERS
|
|||||||
widgets/osd.h
|
widgets/osd.h
|
||||||
widgets/osdpretty.h
|
widgets/osdpretty.h
|
||||||
widgets/renametablineedit.h
|
widgets/renametablineedit.h
|
||||||
widgets/sliderwidget.h
|
widgets/volumeslider.h
|
||||||
widgets/stickyslider.h
|
widgets/stickyslider.h
|
||||||
widgets/stretchheaderview.h
|
widgets/stretchheaderview.h
|
||||||
widgets/trackslider.h
|
widgets/trackslider.h
|
||||||
@@ -571,12 +569,6 @@ optional_source(HAVE_PHONON
|
|||||||
HEADERS engine/phononengine.h
|
HEADERS engine/phononengine.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deezer
|
|
||||||
optional_source(HAVE_DEEZER
|
|
||||||
SOURCES engine/deezerengine.cpp
|
|
||||||
HEADERS engine/deezerengine.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# DBUS and MPRIS - Unix specific
|
# DBUS and MPRIS - Unix specific
|
||||||
if(UNIX AND HAVE_DBUS)
|
if(UNIX AND HAVE_DBUS)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
|
||||||
@@ -880,19 +872,6 @@ optional_source(HAVE_STREAM_TIDAL
|
|||||||
settings/tidalsettingspage.ui
|
settings/tidalsettingspage.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
optional_source(HAVE_STREAM_DEEZER
|
|
||||||
SOURCES
|
|
||||||
deezer/deezerservice.cpp
|
|
||||||
deezer/deezerurlhandler.cpp
|
|
||||||
settings/deezersettingspage.cpp
|
|
||||||
HEADERS
|
|
||||||
deezer/deezerservice.h
|
|
||||||
deezer/deezerurlhandler.h
|
|
||||||
settings/deezersettingspage.h
|
|
||||||
UI
|
|
||||||
settings/deezersettingspage.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
|
||||||
|
|
||||||
@@ -900,6 +879,37 @@ qt5_wrap_cpp(MOC ${HEADERS})
|
|||||||
qt5_wrap_ui(UIC ${UI})
|
qt5_wrap_ui(UIC ${UI})
|
||||||
qt5_add_resources(QRC ${RESOURCES})
|
qt5_add_resources(QRC ${RESOURCES})
|
||||||
|
|
||||||
|
if(HAVE_TRANSLATIONS)
|
||||||
|
|
||||||
|
set(LINGUAS "All" CACHE STRING "A space-seperated list of translations to compile in to Strawberry, or \"None\".")
|
||||||
|
if (LINGUAS STREQUAL "All")
|
||||||
|
# build LANGUAGES from all existing .po files
|
||||||
|
file(GLOB pofiles translations/*.po)
|
||||||
|
foreach(pofile ${pofiles})
|
||||||
|
get_filename_component(lang ${pofile} NAME_WE)
|
||||||
|
list(APPEND LANGUAGES ${lang})
|
||||||
|
endforeach(pofile)
|
||||||
|
else (LINGUAS STREQUAL "All")
|
||||||
|
if (NOT LINGUAS OR LINGUAS STREQUAL "None")
|
||||||
|
set (LANGUAGES "")
|
||||||
|
else (NOT LINGUAS OR LINGUAS STREQUAL "None")
|
||||||
|
string(REGEX MATCHALL [a-zA-Z_@]+ LANGUAGES ${LINGUAS})
|
||||||
|
endif (NOT LINGUAS OR LINGUAS STREQUAL "None")
|
||||||
|
endif (LINGUAS STREQUAL "All")
|
||||||
|
|
||||||
|
add_pot(POT
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/translations/header
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.pot
|
||||||
|
${SOURCES}
|
||||||
|
${MOC}
|
||||||
|
${UIC}
|
||||||
|
${OTHER_SOURCES}
|
||||||
|
../data/html/oauthsuccess.html
|
||||||
|
)
|
||||||
|
add_po(PO strawberry_ LANGUAGES ${LANGUAGES} DIRECTORY translations)
|
||||||
|
|
||||||
|
endif(HAVE_TRANSLATIONS)
|
||||||
|
|
||||||
add_library(strawberry_lib STATIC
|
add_library(strawberry_lib STATIC
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
${MOC}
|
${MOC}
|
||||||
@@ -955,14 +965,6 @@ if(HAVE_PHONON)
|
|||||||
target_link_libraries(strawberry_lib ${PHONON_LIBRARIES})
|
target_link_libraries(strawberry_lib ${PHONON_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_DEEZER)
|
|
||||||
target_link_libraries(strawberry_lib ${LIBDEEZER_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_DZMEDIA)
|
|
||||||
target_link_libraries(strawberry_lib ${LIBDZMEDIA_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_LIBGPOD)
|
if(HAVE_LIBGPOD)
|
||||||
target_link_libraries(strawberry_lib ${LIBGPOD_LIBRARIES})
|
target_link_libraries(strawberry_lib ${LIBGPOD_LIBRARIES})
|
||||||
endif(HAVE_LIBGPOD)
|
endif(HAVE_LIBGPOD)
|
||||||
|
|||||||
@@ -1,32 +1,40 @@
|
|||||||
/***************************************************************************
|
/*
|
||||||
viswidget.cpp - description
|
Strawberry Music Player
|
||||||
-------------------
|
This file was part of Amarok.
|
||||||
begin : Die Jan 7 2003
|
Copyright 2003-2004, Max Howell <max.howell@methylblue.com>
|
||||||
copyright : (C) 2003 by Max Howell
|
Copyright 2009-2012, David Sansome <me@davidsansome.com>
|
||||||
email : markey@web.de
|
Copyright 2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
***************************************************************************/
|
Copyright 2017, Santiago Gil
|
||||||
|
|
||||||
/***************************************************************************
|
Strawberry is free software: you can redistribute it and/or modify
|
||||||
* *
|
it under the terms of the GNU General Public License as published by
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
* it under the terms of the GNU General Public License as published by *
|
(at your option) any later version.
|
||||||
* the Free Software Foundation; either version 2 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "analyzerbase.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QVector>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
#include <QtEvents>
|
#include <QtEvents>
|
||||||
|
|
||||||
#include "analyzerbase.h"
|
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
|
|
||||||
@@ -36,10 +44,11 @@
|
|||||||
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the widget when you return control to it
|
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the widget when you return control to it
|
||||||
// 4. if you want to manipulate the scope, reimplement transform()
|
// 4. if you want to manipulate the scope, reimplement transform()
|
||||||
// 5. for convenience <vector> <qpixmap.h> <qwdiget.h> are pre-included
|
// 5. for convenience <vector> <qpixmap.h> <qwdiget.h> are pre-included
|
||||||
// TODO make an INSTRUCTIONS file
|
//
|
||||||
|
// TODO:
|
||||||
|
// Make an INSTRUCTIONS file
|
||||||
// can't mod scope in analyze you have to use transform
|
// can't mod scope in analyze you have to use transform
|
||||||
|
// for 2D use setErasePixmap Qt function insetead of m_background
|
||||||
// TODO for 2D use setErasePixmap Qt function insetead of m_background
|
|
||||||
|
|
||||||
// make the linker happy only for gcc < 4.0
|
// make the linker happy only for gcc < 4.0
|
||||||
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
|
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
|
||||||
@@ -53,7 +62,6 @@ Analyzer::Base::Base(QWidget *parent, uint scopeSize)
|
|||||||
fht_(new FHT(scopeSize)),
|
fht_(new FHT(scopeSize)),
|
||||||
engine_(nullptr),
|
engine_(nullptr),
|
||||||
lastscope_(512),
|
lastscope_(512),
|
||||||
current_chunk_(0),
|
|
||||||
new_frame_(false),
|
new_frame_(false),
|
||||||
is_playing_(false) {}
|
is_playing_(false) {}
|
||||||
|
|
||||||
@@ -63,19 +71,18 @@ void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
|
|||||||
|
|
||||||
void Analyzer::Base::transform(Scope& scope) {
|
void Analyzer::Base::transform(Scope& scope) {
|
||||||
|
|
||||||
// This is a standard transformation that should give an FFT scope that has bands for pretty analyzers
|
QVector<float> aux(fht_->size());
|
||||||
|
if (aux.size() >= scope.size()) {
|
||||||
|
std::copy(scope.begin(), scope.end(), aux.begin());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::copy(scope.begin(), scope.begin() + aux.size(), aux.begin());
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Resizing here is redundant as FHT routines only calculate FHT::size() values scope.resize( fht_->size() );
|
fht_->logSpectrum(scope.data(), aux.data());
|
||||||
|
fht_->scale(scope.data(), 1.0 / 20);
|
||||||
float *front = static_cast<float*>(&scope.front());
|
|
||||||
|
|
||||||
float *f = new float[fht_->size()];
|
|
||||||
fht_->copy(&f[0], front);
|
|
||||||
fht_->logSpectrum(front, &f[0]);
|
|
||||||
fht_->scale(front, 1.0 / 20);
|
|
||||||
|
|
||||||
scope.resize(fht_->size() / 2); // second half of values are rubbish
|
scope.resize(fht_->size() / 2); // second half of values are rubbish
|
||||||
delete[] f;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
// Maintainer: Max Howell <max.howell@methylblue.com>, (C) 2004
|
/*
|
||||||
// Copyright: See COPYING file that comes with this distribution
|
Strawberry Music Player
|
||||||
|
This file was part of Amarok.
|
||||||
|
Copyright 2003-2004, Max Howell <max.howell@methylblue.com>
|
||||||
|
Copyright 2009-2012, David Sansome <me@davidsansome.com>
|
||||||
|
Copyright 2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
Copyright 2017, Santiago Gil
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef ANALYZERBASE_H
|
#ifndef ANALYZERBASE_H
|
||||||
#define ANALYZERBASE_H
|
#define ANALYZERBASE_H
|
||||||
@@ -7,7 +26,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
#include <sys/types.h>
|
# include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -23,6 +42,7 @@
|
|||||||
|
|
||||||
#include "analyzer/fht.h"
|
#include "analyzer/fht.h"
|
||||||
#include "engine/engine_fwd.h"
|
#include "engine/engine_fwd.h"
|
||||||
|
#include "engine/enginebase.h"
|
||||||
|
|
||||||
class QHideEvent;
|
class QHideEvent;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
@@ -54,7 +74,7 @@ class Base : public QWidget {
|
|||||||
virtual void framerateChanged() {}
|
virtual void framerateChanged() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Base(QWidget*, uint scopeSize = 7);
|
explicit Base(QWidget*, uint scopeSize = 7);
|
||||||
|
|
||||||
void hideEvent(QHideEvent*);
|
void hideEvent(QHideEvent*);
|
||||||
void showEvent(QShowEvent*);
|
void showEvent(QShowEvent*);
|
||||||
@@ -76,7 +96,7 @@ class Base : public QWidget {
|
|||||||
FHT *fht_;
|
FHT *fht_;
|
||||||
EngineBase *engine_;
|
EngineBase *engine_;
|
||||||
Scope lastscope_;
|
Scope lastscope_;
|
||||||
int current_chunk_;
|
|
||||||
bool new_frame_;
|
bool new_frame_;
|
||||||
bool is_playing_;
|
bool is_playing_;
|
||||||
};
|
};
|
||||||
@@ -84,6 +104,7 @@ class Base : public QWidget {
|
|||||||
void interpolate(const Scope&, Scope&);
|
void interpolate(const Scope&, Scope&);
|
||||||
void initSin(Scope&, const uint = 6000);
|
void initSin(Scope&, const uint = 6000);
|
||||||
|
|
||||||
} // END namespace Analyzer
|
} // namespace Analyzer
|
||||||
|
|
||||||
|
#endif // ANALYZERBASE_H
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
#include "analyzerbase.h"
|
#include "analyzerbase.h"
|
||||||
#include "blockanalyzer.h"
|
#include "blockanalyzer.h"
|
||||||
|
#include "boomanalyzer.h"
|
||||||
|
#include "rainbowanalyzer.h"
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
@@ -64,6 +66,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
|||||||
ignore_next_click_(false),
|
ignore_next_click_(false),
|
||||||
current_analyzer_(nullptr),
|
current_analyzer_(nullptr),
|
||||||
engine_(nullptr) {
|
engine_(nullptr) {
|
||||||
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -79,6 +82,9 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
|||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
|
|
||||||
AddAnalyzerType<BlockAnalyzer>();
|
AddAnalyzerType<BlockAnalyzer>();
|
||||||
|
AddAnalyzerType<BoomAnalyzer>();
|
||||||
|
AddAnalyzerType<Rainbow::NyanCatAnalyzer>();
|
||||||
|
AddAnalyzerType<Rainbow::RainbowDashAnalyzer>();
|
||||||
|
|
||||||
connect(mapper_, SIGNAL(mapped(int)), SLOT(ChangeAnalyzer(int)));
|
connect(mapper_, SIGNAL(mapped(int)), SLOT(ChangeAnalyzer(int)));
|
||||||
disable_action_ = context_menu_->addAction(tr("No analyzer"), this, SLOT(DisableAnalyzer()));
|
disable_action_ = context_menu_->addAction(tr("No analyzer"), this, SLOT(DisableAnalyzer()));
|
||||||
@@ -93,6 +99,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
|
|||||||
connect(double_click_timer_, SIGNAL(timeout()), SLOT(ShowPopupMenu()));
|
connect(double_click_timer_, SIGNAL(timeout()), SLOT(ShowPopupMenu()));
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::SetActions(QAction *visualisation) {
|
void AnalyzerContainer::SetActions(QAction *visualisation) {
|
||||||
@@ -101,6 +108,7 @@ void AnalyzerContainer::SetActions(QAction *visualisation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
if (e->button() == Qt::LeftButton) {
|
if (e->button() == Qt::LeftButton) {
|
||||||
if (ignore_next_click_) {
|
if (ignore_next_click_) {
|
||||||
ignore_next_click_ = false;
|
ignore_next_click_ = false;
|
||||||
@@ -114,6 +122,7 @@ void AnalyzerContainer::mouseReleaseEvent(QMouseEvent *e) {
|
|||||||
else if (e->button() == Qt::RightButton) {
|
else if (e->button() == Qt::RightButton) {
|
||||||
context_menu_->popup(e->globalPos());
|
context_menu_->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::ShowPopupMenu() {
|
void AnalyzerContainer::ShowPopupMenu() {
|
||||||
@@ -144,6 +153,7 @@ void AnalyzerContainer::DisableAnalyzer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::ChangeAnalyzer(int id) {
|
void AnalyzerContainer::ChangeAnalyzer(int id) {
|
||||||
|
|
||||||
QObject *instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
|
QObject *instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
@@ -161,9 +171,11 @@ void AnalyzerContainer::ChangeAnalyzer(int id) {
|
|||||||
layout()->addWidget(current_analyzer_);
|
layout()->addWidget(current_analyzer_);
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::ChangeFramerate(int new_framerate) {
|
void AnalyzerContainer::ChangeFramerate(int new_framerate) {
|
||||||
|
|
||||||
if (current_analyzer_) {
|
if (current_analyzer_) {
|
||||||
// Even if it is not supposed to happen, I don't want to get a dbz error
|
// Even if it is not supposed to happen, I don't want to get a dbz error
|
||||||
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
|
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
|
||||||
@@ -173,14 +185,18 @@ void AnalyzerContainer::ChangeFramerate(int new_framerate) {
|
|||||||
current_analyzer_->framerateChanged();
|
current_analyzer_->framerateChanged();
|
||||||
}
|
}
|
||||||
SaveFramerate(new_framerate);
|
SaveFramerate(new_framerate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::Load() {
|
void AnalyzerContainer::Load() {
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
|
QString type = s.value("type", "BlockAnalyzer").toString();
|
||||||
|
current_framerate_ = s.value(kSettingsFramerate, kMediumFramerate).toInt();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
// Analyzer
|
// Analyzer
|
||||||
QString type = s.value("type", "BlockAnalyzer").toString();
|
|
||||||
if (type.isEmpty()) {
|
if (type.isEmpty()) {
|
||||||
DisableAnalyzer();
|
DisableAnalyzer();
|
||||||
disable_action_->setChecked(true);
|
disable_action_->setChecked(true);
|
||||||
@@ -196,7 +212,6 @@ void AnalyzerContainer::Load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Framerate
|
// Framerate
|
||||||
current_framerate_ = s.value(kSettingsFramerate, kMediumFramerate).toInt();
|
|
||||||
for (int i = 0; i < framerate_list_.count(); ++i) {
|
for (int i = 0; i < framerate_list_.count(); ++i) {
|
||||||
if (current_framerate_ == framerate_list_[i]) {
|
if (current_framerate_ == framerate_list_[i]) {
|
||||||
ChangeFramerate(current_framerate_);
|
ChangeFramerate(current_framerate_);
|
||||||
@@ -204,27 +219,35 @@ void AnalyzerContainer::Load() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::SaveFramerate(int framerate) {
|
void AnalyzerContainer::SaveFramerate(int framerate) {
|
||||||
|
|
||||||
// For now, framerate is common for all analyzers. Maybe each analyzer should have its own framerate?
|
// For now, framerate is common for all analyzers. Maybe each analyzer should have its own framerate?
|
||||||
current_framerate_ = framerate;
|
current_framerate_ = framerate;
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue(kSettingsFramerate, current_framerate_);
|
s.setValue(kSettingsFramerate, current_framerate_);
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::Save() {
|
void AnalyzerContainer::Save() {
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
|
|
||||||
s.setValue("type", current_analyzer_ ? current_analyzer_->metaObject()->className() : QVariant());
|
s.setValue("type", current_analyzer_ ? current_analyzer_->metaObject()->className() : QVariant());
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzerContainer::AddFramerate(const QString& name, int framerate) {
|
void AnalyzerContainer::AddFramerate(const QString& name, int framerate) {
|
||||||
|
|
||||||
QAction *action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
|
QAction *action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
|
||||||
mapper_framerate_->setMapping(action, framerate);
|
mapper_framerate_->setMapping(action, framerate);
|
||||||
group_framerate_->addAction(action);
|
group_framerate_->addAction(action);
|
||||||
framerate_list_ << framerate;
|
framerate_list_ << framerate;
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,12 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QSignalMapper>
|
#include <QSignalMapper>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QtEvents>
|
#include <QtEvents>
|
||||||
@@ -120,5 +120,4 @@ void AnalyzerContainer::AddAnalyzerType() {
|
|||||||
actions_ << action;
|
actions_ << action;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // ANALYZERCONTAINER_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,30 @@
|
|||||||
// Author: Max Howell <max.howell@methylblue.com>, (C) 2003-5
|
/*
|
||||||
// Mark Kretschmann <markey@web.de>, (C) 2005
|
Strawberry Music Player
|
||||||
// Copyright: See COPYING file that comes with this distribution
|
This file was part of Amarok.
|
||||||
//
|
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||||
|
Copyright 2005, Mark Kretschmann <markey@web.de>
|
||||||
|
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#include "blockanalyzer.h"
|
#include "blockanalyzer.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <scoped_allocator>
|
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
@@ -19,12 +36,12 @@
|
|||||||
#include "analyzerbase.h"
|
#include "analyzerbase.h"
|
||||||
#include "fht.h"
|
#include "fht.h"
|
||||||
|
|
||||||
const uint BlockAnalyzer::HEIGHT = 2;
|
const uint BlockAnalyzer::kHeight = 2;
|
||||||
const uint BlockAnalyzer::WIDTH = 4;
|
const uint BlockAnalyzer::kWidth = 4;
|
||||||
const uint BlockAnalyzer::MIN_ROWS = 3; // arbituary
|
const uint BlockAnalyzer::kMinRows = 3; // arbituary
|
||||||
const uint BlockAnalyzer::MIN_COLUMNS = 32; // arbituary
|
const uint BlockAnalyzer::kMinColumns = 32; // arbituary
|
||||||
const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n
|
const uint BlockAnalyzer::kMaxColumns = 256; // must be 2**n
|
||||||
const uint BlockAnalyzer::FADE_SIZE = 90;
|
const uint BlockAnalyzer::kFadeSize = 90;
|
||||||
|
|
||||||
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
||||||
|
|
||||||
@@ -34,18 +51,18 @@ BlockAnalyzer::BlockAnalyzer(QWidget *parent)
|
|||||||
rows_(0),
|
rows_(0),
|
||||||
y_(0),
|
y_(0),
|
||||||
barpixmap_(1, 1),
|
barpixmap_(1, 1),
|
||||||
topbarpixmap_(WIDTH, HEIGHT),
|
topbarpixmap_(kWidth, kHeight),
|
||||||
scope_(MIN_COLUMNS),
|
scope_(kMinColumns),
|
||||||
store_(1 << 8, 0),
|
store_(1 << 8, 0),
|
||||||
fade_bars_(FADE_SIZE),
|
fade_bars_(kFadeSize),
|
||||||
fade_pos_(1 << 8, 50),
|
fade_pos_(1 << 8, 50),
|
||||||
fade_intensity_(1 << 8, 32) {
|
fade_intensity_(1 << 8, 32) {
|
||||||
|
|
||||||
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1, MIN_ROWS * (HEIGHT + 1) - 1); //-1 is padding, no drawing takes place there
|
setMinimumSize(kMinColumns * (kWidth + 1) - 1, kMinRows * (kHeight + 1) - 1); //-1 is padding, no drawing takes place there
|
||||||
setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1);
|
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
||||||
|
|
||||||
// mxcl says null pixmaps cause crashes, so let's play it safe
|
// mxcl says null pixmaps cause crashes, so let's play it safe
|
||||||
for (uint i = 0; i < FADE_SIZE; ++i) fade_bars_[i] = QPixmap(1, 1);
|
for (uint i = 0; i < kFadeSize; ++i) fade_bars_[i] = QPixmap(1, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,20 +78,20 @@ void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
|
|||||||
const uint oldRows = rows_;
|
const uint oldRows = rows_;
|
||||||
|
|
||||||
// all is explained in analyze()..
|
// all is explained in analyze()..
|
||||||
//+1 to counter -1 in maxSizes, trust me we need this!
|
// +1 to counter -1 in maxSizes, trust me we need this!
|
||||||
columns_ = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
|
columns_ = qMin(static_cast<uint>(static_cast<double>(width() + 1) / (kWidth + 1)) + 1, kMaxColumns);
|
||||||
rows_ = uint(double(height() + 1) / (HEIGHT + 1));
|
rows_ = static_cast<uint>(static_cast<double>(height() + 1) / (kHeight + 1));
|
||||||
|
|
||||||
// this is the y-offset for drawing from the top of the widget
|
// this is the y-offset for drawing from the top of the widget
|
||||||
y_ = (height() - (rows_ * (HEIGHT + 1)) + 2) / 2;
|
y_ = (height() - (rows_ * (kHeight + 1)) + 2) / 2;
|
||||||
|
|
||||||
scope_.resize(columns_);
|
scope_.resize(columns_);
|
||||||
|
|
||||||
if (rows_ != oldRows) {
|
if (rows_ != oldRows) {
|
||||||
barpixmap_ = QPixmap(WIDTH, rows_ * (HEIGHT + 1));
|
barpixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1));
|
||||||
|
|
||||||
for (uint i = 0; i < FADE_SIZE; ++i)
|
for (uint i = 0; i < kFadeSize; ++i)
|
||||||
fade_bars_[i] = QPixmap(WIDTH, rows_ * (HEIGHT + 1));
|
fade_bars_[i] = QPixmap(kWidth, rows_ * (kHeight + 1));
|
||||||
|
|
||||||
yscale_.resize(rows_ + 1);
|
yscale_.resize(rows_ + 1);
|
||||||
|
|
||||||
@@ -113,13 +130,11 @@ void BlockAnalyzer::transform(Analyzer::Scope &s) {
|
|||||||
|
|
||||||
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
|
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
|
||||||
|
|
||||||
float* front = static_cast<float*>(&s.front());
|
fht_->spectrum(s.data());
|
||||||
|
fht_->scale(s.data(), 1.0 / 20);
|
||||||
fht_->spectrum(front);
|
|
||||||
fht_->scale(front, 1.0 / 20);
|
|
||||||
|
|
||||||
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
|
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
|
||||||
s.resize(scope_.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : scope_.size());
|
s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,35 +169,33 @@ void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_fram
|
|||||||
// determine y
|
// determine y
|
||||||
for (y = 0; scope_[x] < yscale_[y]; ++y) continue;
|
for (y = 0; scope_[x] < yscale_[y]; ++y) continue;
|
||||||
|
|
||||||
// this is opposite to what you'd think, higher than y means the bar is lower than y (physically)
|
// This is opposite to what you'd think, higher than y means the bar is lower than y (physically)
|
||||||
if ((float)y > store_[x])
|
if (static_cast<float>(y) > store_[x])
|
||||||
y = int(store_[x] += step_);
|
y = static_cast<int>(store_[x] += step_);
|
||||||
else
|
else
|
||||||
store_[x] = y;
|
store_[x] = y;
|
||||||
|
|
||||||
// if y is lower than fade_pos_, then the bar has exceeded the height of the fadeout
|
// If y is lower than fade_pos_, then the bar has exceeded the height of the fadeout
|
||||||
// if the fadeout is quite faded now, then display the new one
|
// if the fadeout is quite faded now, then display the new one
|
||||||
if (y <= fade_pos_[x] /*|| fade_intensity_[x] < FADE_SIZE / 3*/) {
|
if (y <= fade_pos_[x] /*|| fade_intensity_[x] < kFadeSize / 3*/) {
|
||||||
fade_pos_[x] = y;
|
fade_pos_[x] = y;
|
||||||
fade_intensity_[x] = FADE_SIZE;
|
fade_intensity_[x] = kFadeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade_intensity_[x] > 0) {
|
if (fade_intensity_[x] > 0) {
|
||||||
const uint offset = --fade_intensity_[x];
|
const uint offset = --fade_intensity_[x];
|
||||||
const uint y = y_ + (fade_pos_[x] * (HEIGHT + 1));
|
const uint y = y_ + (fade_pos_[x] * (kHeight + 1));
|
||||||
canvas_painter.drawPixmap(x * (WIDTH + 1), y, fade_bars_[offset], 0, 0, WIDTH, height() - y);
|
canvas_painter.drawPixmap(x * (kWidth + 1), y, fade_bars_[offset], 0, 0, kWidth, height() - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade_intensity_[x] == 0) fade_pos_[x] = rows_;
|
if (fade_intensity_[x] == 0) fade_pos_[x] = rows_;
|
||||||
|
|
||||||
// REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are
|
// REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are
|
||||||
canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, *bar(),
|
canvas_painter.drawPixmap(x * (kWidth + 1), y * (kHeight + 1) + y_, *bar(), 0, y * (kHeight + 1), bar()->width(), bar()->height());
|
||||||
0, y * (HEIGHT + 1), bar()->width(),
|
|
||||||
bar()->height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint x = 0; x < store_.size(); ++x)
|
for (uint x = 0; x < store_.size(); ++x)
|
||||||
canvas_painter.drawPixmap(x * (WIDTH + 1), int(store_[x]) * (HEIGHT + 1) + y_, topbarpixmap_);
|
canvas_painter.drawPixmap(x * (kWidth + 1), static_cast<int>(store_[x]) * (kHeight + 1) + y_, topbarpixmap_);
|
||||||
|
|
||||||
p.drawPixmap(0, 0, canvas_);
|
p.drawPixmap(0, 0, canvas_);
|
||||||
|
|
||||||
@@ -223,11 +236,11 @@ static inline void adjustToLimits(int &b, int &f, uint &amount) {
|
|||||||
* It won't modify the hue of fg unless absolutely necessary
|
* It won't modify the hue of fg unless absolutely necessary
|
||||||
* @return the adjusted form of fg
|
* @return the adjusted form of fg
|
||||||
*/
|
*/
|
||||||
QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) {
|
QColor ensureContrast(const QColor &bg, const QColor &fg, uint amount = 150) {
|
||||||
|
|
||||||
class OutputOnExit {
|
class OutputOnExit {
|
||||||
public:
|
public:
|
||||||
OutputOnExit(const QColor &color) : c(color) {}
|
explicit OutputOnExit(const QColor &color) : c(color) {}
|
||||||
~OutputOnExit() {
|
~OutputOnExit() {
|
||||||
int h, s, v;
|
int h, s, v;
|
||||||
c.getHsv(&h, &s, &v);
|
c.getHsv(&h, &s, &v);
|
||||||
@@ -237,14 +250,6 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) {
|
|||||||
const QColor &c;
|
const QColor &c;
|
||||||
};
|
};
|
||||||
|
|
||||||
// hack so I don't have to cast everywhere
|
|
||||||
#define amount static_cast<int>(_amount)
|
|
||||||
// #define STAMP debug() << (QValueList<int>() << fh << fs << fv) << endl;
|
|
||||||
// #define STAMP1( string ) debug() << string << ": " <<
|
|
||||||
// (QValueList<int>() << fh << fs << fv) << endl;
|
|
||||||
// #define STAMP2( string, value ) debug() << string << "=" << value << ":
|
|
||||||
// " << (QValueList<int>() << fh << fs << fv) << endl;
|
|
||||||
|
|
||||||
OutputOnExit allocateOnTheStack(fg);
|
OutputOnExit allocateOnTheStack(fg);
|
||||||
|
|
||||||
int bh, bs, bv;
|
int bh, bs, bv;
|
||||||
@@ -255,23 +260,17 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) {
|
|||||||
|
|
||||||
int dv = abs(bv - fv);
|
int dv = abs(bv - fv);
|
||||||
|
|
||||||
// STAMP2( "DV", dv );
|
|
||||||
|
|
||||||
// value is the best measure of contrast
|
// value is the best measure of contrast
|
||||||
// if there is enough difference in value already, return fg unchanged
|
// if there is enough difference in value already, return fg unchanged
|
||||||
if (dv > amount) return fg;
|
if (dv > static_cast<int>(amount)) return fg;
|
||||||
|
|
||||||
int ds = abs(bs - fs);
|
int ds = abs(bs - fs);
|
||||||
|
|
||||||
// STAMP2( "DS", ds );
|
|
||||||
|
|
||||||
// saturation is good enough too. But not as good. TODO adapt this a little
|
// saturation is good enough too. But not as good. TODO adapt this a little
|
||||||
if (ds > amount) return fg;
|
if (ds > static_cast<int>(amount)) return fg;
|
||||||
|
|
||||||
int dh = abs(bh - fh);
|
int dh = abs(bh - fh);
|
||||||
|
|
||||||
// STAMP2( "DH", dh );
|
|
||||||
|
|
||||||
if (dh > 120) {
|
if (dh > 120) {
|
||||||
// a third of the colour wheel automatically guarentees contrast
|
// a third of the colour wheel automatically guarentees contrast
|
||||||
// but only if the values are high enough and saturations significant enough
|
// but only if the values are high enough and saturations significant enough
|
||||||
@@ -279,79 +278,49 @@ QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) {
|
|||||||
|
|
||||||
// check the saturation for the two colours is sufficient that hue alone can
|
// check the saturation for the two colours is sufficient that hue alone can
|
||||||
// provide sufficient contrast
|
// provide sufficient contrast
|
||||||
if (ds > amount / 2 && (bs > 125 && fs > 125))
|
if (ds > static_cast<int>(amount) / 2 && (bs > 125 && fs > 125))
|
||||||
// STAMP1( "Sufficient saturation difference, and hues are
|
|
||||||
// compliemtary" );
|
|
||||||
return fg;
|
return fg;
|
||||||
else if (dv > amount / 2 && (bv > 125 && fv > 125))
|
else if (dv > static_cast<int>(amount) / 2 && (bv > 125 && fv > 125))
|
||||||
// STAMP1( "Sufficient value difference, and hues are
|
|
||||||
// compliemtary" );
|
|
||||||
return fg;
|
return fg;
|
||||||
|
|
||||||
// STAMP1( "Hues are complimentary but we must modify the value or
|
|
||||||
// saturation of the contrasting colour" );
|
|
||||||
|
|
||||||
// but either the colours are two desaturated, or too dark
|
|
||||||
// so we need to adjust the system, although not as much
|
|
||||||
///_amount /= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs < 50 && ds < 40) {
|
if (fs < 50 && ds < 40) {
|
||||||
// low saturation on a low saturation is sad
|
// low saturation on a low saturation is sad
|
||||||
const int tmp = 50 - fs;
|
const int tmp = 50 - fs;
|
||||||
fs = 50;
|
fs = 50;
|
||||||
if (amount > tmp)
|
if (static_cast<int>(amount) > tmp)
|
||||||
_amount -= tmp;
|
amount -= tmp;
|
||||||
else
|
else
|
||||||
_amount = 0;
|
amount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that there is available value to honor our contrast requirement
|
// test that there is available value to honor our contrast requirement
|
||||||
if (255 - dv < amount) {
|
if (255 - dv < static_cast<int>(amount)) {
|
||||||
// we have to modify the value and saturation of fg
|
// we have to modify the value and saturation of fg
|
||||||
// adjustToLimits( bv, fv, amount );
|
// adjustToLimits( bv, fv, amount );
|
||||||
|
|
||||||
// STAMP
|
|
||||||
|
|
||||||
// see if we need to adjust the saturation
|
// see if we need to adjust the saturation
|
||||||
if (amount > 0) adjustToLimits(bs, fs, _amount);
|
if (static_cast<int>(amount) > 0) adjustToLimits(bs, fs, amount);
|
||||||
|
|
||||||
// STAMP
|
|
||||||
|
|
||||||
// see if we need to adjust the hue
|
// see if we need to adjust the hue
|
||||||
if (amount > 0) fh += amount; // cycles around;
|
if (static_cast<int>(amount) > 0)
|
||||||
|
fh += static_cast<int>(amount); // cycles around;
|
||||||
// STAMP
|
|
||||||
|
|
||||||
return QColor::fromHsv(fh, fs, fv);
|
return QColor::fromHsv(fh, fs, fv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STAMP
|
if (fv > bv && bv > static_cast<int>(amount))
|
||||||
|
return QColor::fromHsv(fh, fs, bv - static_cast<int>(amount));
|
||||||
|
|
||||||
if (fv > bv && bv > amount) return QColor::fromHsv(fh, fs, bv - amount);
|
if (fv < bv && fv > static_cast<int>(amount))
|
||||||
|
return QColor::fromHsv(fh, fs, fv - static_cast<int>(amount));
|
||||||
|
|
||||||
// STAMP
|
if (fv > bv && (255 - fv > static_cast<int>(amount)))
|
||||||
|
return QColor::fromHsv(fh, fs, fv + static_cast<int>(amount));
|
||||||
|
|
||||||
if (fv < bv && fv > amount) return QColor::fromHsv(fh, fs, fv - amount);
|
if (fv < bv && (255 - bv > static_cast<int>(amount)))
|
||||||
|
return QColor::fromHsv(fh, fs, bv + static_cast<int>(amount));
|
||||||
// STAMP
|
|
||||||
|
|
||||||
if (fv > bv && (255 - fv > amount))
|
|
||||||
return QColor::fromHsv(fh, fs, fv + amount);
|
|
||||||
|
|
||||||
// STAMP
|
|
||||||
|
|
||||||
if (fv < bv && (255 - bv > amount))
|
|
||||||
return QColor::fromHsv(fh, fs, bv + amount);
|
|
||||||
|
|
||||||
// STAMP
|
|
||||||
// debug() << "Something went wrong!\n";
|
|
||||||
|
|
||||||
return Qt::blue;
|
return Qt::blue;
|
||||||
|
|
||||||
#undef amount
|
|
||||||
// #undef STAMP
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockAnalyzer::paletteChange(const QPalette&) {
|
void BlockAnalyzer::paletteChange(const QPalette&) {
|
||||||
@@ -361,17 +330,17 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
|
|||||||
|
|
||||||
topbarpixmap_.fill(fg);
|
topbarpixmap_.fill(fg);
|
||||||
|
|
||||||
const double dr = 15 * double(bg.red() - fg.red()) / (rows_ * 16);
|
const double dr = 15 * static_cast<double>(bg.red() - fg.red()) / (rows_ * 16);
|
||||||
const double dg = 15 * double(bg.green() - fg.green()) / (rows_ * 16);
|
const double dg = 15 * static_cast<double>(bg.green() - fg.green()) / (rows_ * 16);
|
||||||
const double db = 15 * double(bg.blue() - fg.blue()) / (rows_ * 16);
|
const double db = 15 * static_cast<double>(bg.blue() - fg.blue()) / (rows_ * 16);
|
||||||
const int r = fg.red(), g = fg.green(), b = fg.blue();
|
const int r = fg.red(), g = fg.green(), b = fg.blue();
|
||||||
|
|
||||||
bar()->fill(bg);
|
bar()->fill(bg);
|
||||||
|
|
||||||
QPainter p(bar());
|
QPainter p(bar());
|
||||||
for (int y = 0; (uint)y < rows_; ++y)
|
for (int y = 0; static_cast<uint>(y) < rows_; ++y)
|
||||||
// graduate the fg color
|
// graduate the fg color
|
||||||
p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * y), g + int(dg * y), b + int(db * y)));
|
p.fillRect(0, y * (kHeight + 1), kWidth, kHeight, QColor(r + static_cast<int>(dr * y), g + static_cast<int>(dg * y), b + static_cast<int>(db * y)));
|
||||||
|
|
||||||
{
|
{
|
||||||
const QColor bg = palette().color(QPalette::Background).dark(112);
|
const QColor bg = palette().color(QPalette::Background).dark(112);
|
||||||
@@ -388,12 +357,12 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
|
|||||||
const int r = bg.red(), g = bg.green(), b = bg.blue();
|
const int r = bg.red(), g = bg.green(), b = bg.blue();
|
||||||
|
|
||||||
// Precalculate all fade-bar pixmaps
|
// Precalculate all fade-bar pixmaps
|
||||||
for (uint y = 0; y < FADE_SIZE; ++y) {
|
for (uint y = 0; y < kFadeSize; ++y) {
|
||||||
fade_bars_[y].fill(palette().color(QPalette::Background));
|
fade_bars_[y].fill(palette().color(QPalette::Background));
|
||||||
QPainter f(&fade_bars_[y]);
|
QPainter f(&fade_bars_[y]);
|
||||||
for (int z = 0; (uint)z < rows_; ++z) {
|
for (int z = 0; static_cast<uint>(z) < rows_; ++z) {
|
||||||
const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE));
|
const double Y = 1.0 - (log10(kFadeSize - y) / log10(kFadeSize));
|
||||||
f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * Y), g + int(dg * Y), b + int(db * Y)));
|
f.fillRect(0, z * (kHeight + 1), kWidth, kHeight, QColor(r + static_cast<int>(dr * Y), g + static_cast<int>(dg * Y), b + static_cast<int>(db * Y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,14 +373,21 @@ void BlockAnalyzer::paletteChange(const QPalette&) {
|
|||||||
|
|
||||||
void BlockAnalyzer::drawBackground() {
|
void BlockAnalyzer::drawBackground() {
|
||||||
|
|
||||||
|
if (background_.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const QColor bg = palette().color(QPalette::Background);
|
const QColor bg = palette().color(QPalette::Background);
|
||||||
const QColor bgdark = bg.dark(112);
|
const QColor bgdark = bg.dark(112);
|
||||||
|
|
||||||
background_.fill(bg);
|
background_.fill(bg);
|
||||||
|
|
||||||
QPainter p(&background_);
|
QPainter p(&background_);
|
||||||
|
|
||||||
|
if (p.paintEngine() == 0) return;
|
||||||
|
|
||||||
for (int x = 0; (uint)x < columns_; ++x)
|
for (int x = 0; (uint)x < columns_; ++x)
|
||||||
for (int y = 0; (uint)y < rows_; ++y)
|
for (int y = 0; (uint)y < rows_; ++y)
|
||||||
p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, WIDTH, HEIGHT, bgdark);
|
p.fillRect(x * (kWidth + 1), y * (kHeight + 1) + y_, kWidth, kHeight, bgdark);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
// Maintainer: Max Howell <mac.howell@methylblue.com>, (C) 2003-5
|
/*
|
||||||
// Copyright: See COPYING file that comes with this distribution
|
Strawberry Music Player
|
||||||
//
|
This file was part of Amarok.
|
||||||
|
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||||
|
Copyright 2005, Mark Kretschmann <markey@web.de>
|
||||||
|
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef BLOCKANALYZER_H
|
#ifndef BLOCKANALYZER_H
|
||||||
#define BLOCKANALYZER_H
|
#define BLOCKANALYZER_H
|
||||||
@@ -11,6 +30,7 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QVector>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@@ -21,22 +41,18 @@
|
|||||||
|
|
||||||
class QResizeEvent;
|
class QResizeEvent;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Max Howell
|
|
||||||
*/
|
|
||||||
|
|
||||||
class BlockAnalyzer : public Analyzer::Base {
|
class BlockAnalyzer : public Analyzer::Base {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE BlockAnalyzer(QWidget*);
|
Q_INVOKABLE BlockAnalyzer(QWidget*);
|
||||||
~BlockAnalyzer();
|
~BlockAnalyzer();
|
||||||
|
|
||||||
static const uint HEIGHT;
|
static const uint kHeight;
|
||||||
static const uint WIDTH;
|
static const uint kWidth;
|
||||||
static const uint MIN_ROWS;
|
static const uint kMinRows;
|
||||||
static const uint MIN_COLUMNS;
|
static const uint kMinColumns;
|
||||||
static const uint MAX_COLUMNS;
|
static const uint kMaxColumns;
|
||||||
static const uint FADE_SIZE;
|
static const uint kFadeSize;
|
||||||
|
|
||||||
static const char *kName;
|
static const char *kName;
|
||||||
|
|
||||||
@@ -53,22 +69,21 @@ class BlockAnalyzer : public Analyzer::Base {
|
|||||||
private:
|
private:
|
||||||
QPixmap *bar() { return &barpixmap_; }
|
QPixmap *bar() { return &barpixmap_; }
|
||||||
|
|
||||||
uint columns_, rows_; // number of rows and columns of blocks
|
uint columns_, rows_; // number of rows and columns of blocks
|
||||||
uint y_; // y-offset from top of widget
|
uint y_; // y-offset from top of widget
|
||||||
QPixmap barpixmap_;
|
QPixmap barpixmap_;
|
||||||
QPixmap topbarpixmap_;
|
QPixmap topbarpixmap_;
|
||||||
QPixmap background_;
|
QPixmap background_;
|
||||||
QPixmap canvas_;
|
QPixmap canvas_;
|
||||||
Analyzer::Scope scope_; // so we don't create a vector every frame
|
Analyzer::Scope scope_; // so we don't create a vector every frame
|
||||||
std::vector<float> store_; // current bar heights
|
QVector<float> store_; // current bar heights
|
||||||
std::vector<float> yscale_;
|
QVector<float> yscale_;
|
||||||
|
|
||||||
// FIXME why can't I namespace these? c++ issue?
|
QVector<QPixmap> fade_bars_;
|
||||||
std::vector<QPixmap> fade_bars_;
|
QVector<uint> fade_pos_;
|
||||||
std::vector<uint> fade_pos_;
|
QVector<int> fade_intensity_;
|
||||||
std::vector<int> fade_intensity_;
|
|
||||||
|
|
||||||
float step_; // rows to fall per frame
|
float step_; // rows to fall per frame
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // BLOCKANALYZER_H
|
||||||
|
|||||||
169
src/analyzer/boomanalyzer.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
Strawberry Music Player
|
||||||
|
This file was part of Clementine.
|
||||||
|
Copyright 2004, Max Howell <max.howell@methylblue.com>
|
||||||
|
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "boomanalyzer.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
using Analyzer::Scope;
|
||||||
|
|
||||||
|
const uint BoomAnalyzer::kColumnWidth = 4;
|
||||||
|
const uint BoomAnalyzer::kMaxBandCount = 256;
|
||||||
|
const uint BoomAnalyzer::kMinBandCount = 32;
|
||||||
|
|
||||||
|
const char* BoomAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer");
|
||||||
|
|
||||||
|
BoomAnalyzer::BoomAnalyzer(QWidget* parent)
|
||||||
|
: Analyzer::Base(parent, 9),
|
||||||
|
bands_(0),
|
||||||
|
scope_(kMinBandCount),
|
||||||
|
fg_(palette().color(QPalette::Highlight)),
|
||||||
|
K_barHeight_(1.271) // 1.471
|
||||||
|
,
|
||||||
|
F_peakSpeed_(1.103) // 1.122
|
||||||
|
,
|
||||||
|
F_(1.0),
|
||||||
|
bar_height_(kMaxBandCount, 0),
|
||||||
|
peak_height_(kMaxBandCount, 0),
|
||||||
|
peak_speed_(kMaxBandCount, 0.01),
|
||||||
|
barPixmap_(kColumnWidth, 50) {
|
||||||
|
|
||||||
|
setMinimumWidth(kMinBandCount * (kColumnWidth + 1) - 1);
|
||||||
|
setMaximumWidth(kMaxBandCount * (kColumnWidth + 1) - 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoomAnalyzer::changeK_barHeight(int newValue) {
|
||||||
|
K_barHeight_ = static_cast<double>(newValue) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoomAnalyzer::changeF_peakSpeed(int newValue) {
|
||||||
|
F_peakSpeed_ = static_cast<double>(newValue) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoomAnalyzer::resizeEvent(QResizeEvent* e) {
|
||||||
|
|
||||||
|
QWidget::resizeEvent(e);
|
||||||
|
|
||||||
|
const uint HEIGHT = height() - 2;
|
||||||
|
const double h = 1.2 / HEIGHT;
|
||||||
|
|
||||||
|
bands_ = qMin(static_cast<uint>(static_cast<double>(width() + 1) / (kColumnWidth + 1)) + 1, kMaxBandCount);
|
||||||
|
scope_.resize(bands_);
|
||||||
|
|
||||||
|
F_ = static_cast<double>(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
|
||||||
|
|
||||||
|
barPixmap_ = QPixmap(kColumnWidth - 2, HEIGHT);
|
||||||
|
canvas_ = QPixmap(size());
|
||||||
|
canvas_.fill(palette().color(QPalette::Background));
|
||||||
|
|
||||||
|
QPainter p(&barPixmap_);
|
||||||
|
for (uint y = 0; y < HEIGHT; ++y) {
|
||||||
|
const double F = static_cast<double>(y) * h;
|
||||||
|
|
||||||
|
p.setPen(QColor(qMax(0, 255 - static_cast<int>(229.0 * F)),
|
||||||
|
qMax(0, 255 - static_cast<int>(229.0 * F)),
|
||||||
|
qMax(0, 255 - static_cast<int>(191.0 * F))));
|
||||||
|
p.drawLine(0, y, kColumnWidth - 2, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoomAnalyzer::transform(Scope& s) {
|
||||||
|
|
||||||
|
fht_->spectrum(s.data());
|
||||||
|
fht_->scale(s.data(), 1.0 / 50);
|
||||||
|
|
||||||
|
s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2 : scope_.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
|
||||||
|
|
||||||
|
if (!new_frame || engine_->state() == Engine::Paused) {
|
||||||
|
p.drawPixmap(0, 0, canvas_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float h;
|
||||||
|
const uint MAX_HEIGHT = height() - 1;
|
||||||
|
|
||||||
|
QPainter canvas_painter(&canvas_);
|
||||||
|
canvas_.fill(palette().color(QPalette::Background));
|
||||||
|
|
||||||
|
Analyzer::interpolate(scope, scope_);
|
||||||
|
|
||||||
|
for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) {
|
||||||
|
h = log10(scope_[i] * 256.0) * F_;
|
||||||
|
|
||||||
|
if (h > MAX_HEIGHT) h = MAX_HEIGHT;
|
||||||
|
|
||||||
|
if (h > bar_height_[i]) {
|
||||||
|
bar_height_[i] = h;
|
||||||
|
|
||||||
|
if (h > peak_height_[i]) {
|
||||||
|
peak_height_[i] = h;
|
||||||
|
peak_speed_[i] = 0.01;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto peak_handling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (bar_height_[i] > 0.0) {
|
||||||
|
bar_height_[i] -= K_barHeight_; // 1.4
|
||||||
|
if (bar_height_[i] < 0.0) bar_height_[i] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
peak_handling:
|
||||||
|
|
||||||
|
if (peak_height_[i] > 0.0) {
|
||||||
|
peak_height_[i] -= peak_speed_[i];
|
||||||
|
peak_speed_[i] *= F_peakSpeed_; // 1.12
|
||||||
|
|
||||||
|
if (peak_height_[i] < bar_height_[i]) peak_height_[i] = bar_height_[i];
|
||||||
|
if (peak_height_[i] < 0.0) peak_height_[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
y = height() - uint(bar_height_[i]);
|
||||||
|
canvas_painter.drawPixmap(x + 1, y, barPixmap_, 0, y, -1, -1);
|
||||||
|
canvas_painter.setPen(fg_);
|
||||||
|
if (bar_height_[i] > 0)
|
||||||
|
canvas_painter.drawRect(x, y, kColumnWidth - 1, height() - y - 1);
|
||||||
|
|
||||||
|
y = height() - uint(peak_height_[i]);
|
||||||
|
canvas_painter.setPen(palette().color(QPalette::Midlight));
|
||||||
|
canvas_painter.drawLine(x, y, x + kColumnWidth - 1, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.drawPixmap(0, 0, canvas_);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
75
src/analyzer/boomanalyzer.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Strawberry Music Player
|
||||||
|
This file was part of Clementine.
|
||||||
|
Copyright 2004, Max Howell <max.howell@methylblue.com>
|
||||||
|
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||||
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOMANALYZER_H
|
||||||
|
#define BOOMANALYZER_H
|
||||||
|
|
||||||
|
#include "analyzerbase.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
class QResizeEvent;
|
||||||
|
|
||||||
|
class BoomAnalyzer : public Analyzer::Base {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE BoomAnalyzer(QWidget*);
|
||||||
|
|
||||||
|
static const char* kName;
|
||||||
|
|
||||||
|
virtual void transform(Analyzer::Scope& s);
|
||||||
|
virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void changeK_barHeight(int);
|
||||||
|
void changeF_peakSpeed(int);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent* e);
|
||||||
|
|
||||||
|
static const uint kColumnWidth;
|
||||||
|
static const uint kMaxBandCount;
|
||||||
|
static const uint kMinBandCount;
|
||||||
|
|
||||||
|
uint bands_;
|
||||||
|
Analyzer::Scope scope_;
|
||||||
|
QColor fg_;
|
||||||
|
|
||||||
|
double K_barHeight_, F_peakSpeed_, F_;
|
||||||
|
|
||||||
|
std::vector<float> bar_height_;
|
||||||
|
std::vector<float> peak_height_;
|
||||||
|
std::vector<float> peak_speed_;
|
||||||
|
|
||||||
|
QPixmap barPixmap_;
|
||||||
|
QPixmap canvas_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BOOMANALYZER_H
|
||||||
@@ -1,140 +1,140 @@
|
|||||||
// FHT - Fast Hartley Transform Class
|
/*
|
||||||
//
|
Strawberry Music Player
|
||||||
// Copyright (C) 2004 Melchior FRANZ - mfranz@kde.org
|
This file was part of Clementine.
|
||||||
//
|
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
|
||||||
// This program is free software; you can redistribute it and/or
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
// modify it under the terms of the GNU General Public License as
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
Copyright 2017, Santiago Gil
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program 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 this program; if not, write to the Free Software
|
|
||||||
// Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
|
|
||||||
#include <math.h>
|
Strawberry is free software: you can redistribute it and/or modify
|
||||||
#include <string.h>
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "fht.h"
|
#include "fht.h"
|
||||||
|
|
||||||
FHT::FHT(int n) : m_buf(0), m_tab(0), m_log(0) {
|
#include <algorithm>
|
||||||
if (n < 3) {
|
#include <cmath>
|
||||||
m_num = 0;
|
|
||||||
m_exp2 = -1;
|
#include <QVector>
|
||||||
return;
|
|
||||||
}
|
FHT::FHT(int n) : num_((n < 3) ? 0 : 1 << n), exp2_((n < 3) ? -1 : n) {
|
||||||
m_exp2 = n;
|
|
||||||
m_num = 1 << n;
|
|
||||||
if (n > 3) {
|
if (n > 3) {
|
||||||
m_buf = new float[m_num];
|
buf_vector_.resize(num_);
|
||||||
m_tab = new float[m_num * 2];
|
tab_vector_.resize(num_ * 2);
|
||||||
makeCasTable();
|
makeCasTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FHT::~FHT() {
|
FHT::~FHT() {}
|
||||||
delete[] m_buf;
|
|
||||||
delete[] m_tab;
|
int FHT::sizeExp() const { return exp2_; }
|
||||||
delete[] m_log;
|
int FHT::size() const { return num_; }
|
||||||
}
|
|
||||||
|
float* FHT::buf_() { return buf_vector_.data(); }
|
||||||
|
float* FHT::tab_() { return tab_vector_.data(); }
|
||||||
|
int* FHT::log_() { return log_vector_.data(); }
|
||||||
|
|
||||||
void FHT::makeCasTable(void) {
|
void FHT::makeCasTable(void) {
|
||||||
float d, *costab, *sintab;
|
float* costab = tab_();
|
||||||
int ul, ndiv2 = m_num / 2;
|
float* sintab = tab_() + num_ / 2 + 1;
|
||||||
|
|
||||||
for (costab = m_tab, sintab = m_tab + m_num / 2 + 1, ul = 0; ul < m_num; ul++) {
|
for (int ul = 0; ul < num_; ul++) {
|
||||||
d = M_PI * ul / ndiv2;
|
float d = M_PI * ul / (num_ / 2);
|
||||||
*costab = *sintab = cos(d);
|
*costab = *sintab = cos(d);
|
||||||
|
|
||||||
costab += 2, sintab += 2;
|
costab += 2;
|
||||||
if (sintab > m_tab + m_num * 2) sintab = m_tab + 1;
|
sintab += 2;
|
||||||
|
if (sintab > tab_() + num_ * 2) sintab = tab_() + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float* FHT::copy(float* d, float* s) {
|
|
||||||
return (float*)memcpy(d, s, m_num * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
float* FHT::clear(float* d) {
|
|
||||||
return (float*)memset(d, 0, m_num * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FHT::scale(float* p, float d) {
|
void FHT::scale(float* p, float d) {
|
||||||
for (int i = 0; i < (m_num / 2); i++) *p++ *= d;
|
for (int i = 0; i < (num_ / 2); i++) *p++ *= d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::ewma(float* d, float* s, float w) {
|
void FHT::ewma(float* d, float* s, float w) {
|
||||||
for (int i = 0; i < (m_num / 2); i++, d++, s++) *d = *d * w + *s * (1 - w);
|
for (int i = 0; i < (num_ / 2); i++, d++, s++) *d = *d * w + *s * (1 - w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::logSpectrum(float* out, float* p) {
|
void FHT::logSpectrum(float* out, float* p) {
|
||||||
int n = m_num / 2, i, j, k, *r;
|
|
||||||
if (!m_log) {
|
int n = num_ / 2, i, j, k, *r;
|
||||||
m_log = new int[n];
|
if (log_vector_.size() < n) {
|
||||||
float f = n / log10((double)n);
|
log_vector_.resize(n);
|
||||||
for (i = 0, r = m_log; i < n; i++, r++) {
|
float f = n / log10(static_cast<double>(n));
|
||||||
j = int(rint(log10(i + 1.0) * f));
|
for (i = 0, r = log_(); i < n; i++, r++) {
|
||||||
|
j = static_cast<int>(rint(log10(i + 1.0) * f));
|
||||||
*r = j >= n ? n - 1 : j;
|
*r = j >= n ? n - 1 : j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
semiLogSpectrum(p);
|
semiLogSpectrum(p);
|
||||||
*out++ = *p = *p / 100;
|
*out++ = *p = *p / 100;
|
||||||
for (k = i = 1, r = m_log; i < n; i++) {
|
for (k = i = 1, r = log_(); i < n; i++) {
|
||||||
j = *r++;
|
j = *r++;
|
||||||
if (i == j)
|
if (i == j) {
|
||||||
*out++ = p[i];
|
*out++ = p[i];
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
float base = p[k - 1];
|
float base = p[k - 1];
|
||||||
float step = (p[j] - base) / (j - (k - 1));
|
float step = (p[j] - base) / (j - (k - 1));
|
||||||
for (float corr = 0; k <= j; k++, corr += step) *out++ = base + corr;
|
for (float corr = 0; k <= j; k++, corr += step) *out++ = base + corr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::semiLogSpectrum(float* p) {
|
void FHT::semiLogSpectrum(float* p) {
|
||||||
float e;
|
|
||||||
power2(p);
|
power2(p);
|
||||||
for (int i = 0; i < (m_num / 2); i++, p++) {
|
for (int i = 0; i < (num_ / 2); i++, p++) {
|
||||||
e = 10.0 * log10(sqrt(*p * .5));
|
float e = 10.0 * log10(sqrt(*p / 2));
|
||||||
*p = e < 0 ? 0 : e;
|
*p = e < 0 ? 0 : e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::spectrum(float* p) {
|
void FHT::spectrum(float* p) {
|
||||||
power2(p);
|
power2(p);
|
||||||
for (int i = 0; i < (m_num / 2); i++, p++) *p = (float)sqrt(*p * .5);
|
for (int i = 0; i < (num_ / 2); i++, p++)
|
||||||
|
*p = static_cast<float>(sqrt(*p / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::power(float* p) {
|
void FHT::power(float* p) {
|
||||||
power2(p);
|
power2(p);
|
||||||
for (int i = 0; i < (m_num / 2); i++) *p++ *= .5;
|
for (int i = 0; i < (num_ / 2); i++) *p++ /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::power2(float* p) {
|
void FHT::power2(float* p) {
|
||||||
int i;
|
_transform(p, num_, 0);
|
||||||
float* q;
|
|
||||||
_transform(p, m_num, 0);
|
|
||||||
|
|
||||||
*p = (*p * *p), *p += *p, p++;
|
*p = static_cast<float>(2 * pow(*p, 2));
|
||||||
|
p++;
|
||||||
|
|
||||||
for (i = 1, q = p + m_num - 2; i < (m_num / 2); i++, --q)
|
float* q = p + num_ - 2;
|
||||||
*p = (*p * *p) + (*q * *q), p++;
|
for (int i = 1; i < (num_ / 2); i++) {
|
||||||
|
*p = static_cast<float>(pow(*p, 2) + pow(*q, 2));
|
||||||
|
p++;
|
||||||
|
q--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::transform(float* p) {
|
void FHT::transform(float* p) {
|
||||||
if (m_num == 8)
|
if (num_ == 8)
|
||||||
transform8(p);
|
transform8(p);
|
||||||
else
|
else
|
||||||
_transform(p, m_num, 0);
|
_transform(p, num_, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::transform8(float* p) {
|
void FHT::transform8(float* p) {
|
||||||
|
|
||||||
float a, b, c, d, e, f, g, h, b_f2, d_h2;
|
float a, b, c, d, e, f, g, h, b_f2, d_h2;
|
||||||
float a_c_eg, a_ce_g, ac_e_g, aceg, b_df_h, bdfh;
|
float a_c_eg, a_ce_g, ac_e_g, aceg, b_df_h, bdfh;
|
||||||
|
|
||||||
@@ -159,6 +159,7 @@ void FHT::transform8(float* p) {
|
|||||||
*--p = a_ce_g + b_df_h;
|
*--p = a_ce_g + b_df_h;
|
||||||
*--p = ac_e_g + b_f2;
|
*--p = ac_e_g + b_f2;
|
||||||
*--p = aceg + bdfh;
|
*--p = aceg + bdfh;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FHT::_transform(float* p, int n, int k) {
|
void FHT::_transform(float* p, int n, int k) {
|
||||||
@@ -171,19 +172,19 @@ void FHT::_transform(float* p, int n, int k) {
|
|||||||
int i, j, ndiv2 = n / 2;
|
int i, j, ndiv2 = n / 2;
|
||||||
float a, *t1, *t2, *t3, *t4, *ptab, *pp;
|
float a, *t1, *t2, *t3, *t4, *ptab, *pp;
|
||||||
|
|
||||||
for (i = 0, t1 = m_buf, t2 = m_buf + ndiv2, pp = &p[k]; i < ndiv2; i++)
|
for (i = 0, t1 = buf_(), t2 = buf_() + ndiv2, pp = &p[k]; i < ndiv2; i++)
|
||||||
*t1++ = *pp++, *t2++ = *pp++;
|
*t1++ = *pp++, *t2++ = *pp++;
|
||||||
|
|
||||||
memcpy(p + k, m_buf, sizeof(float) * n);
|
std::copy(buf_(), buf_() + n, p + k);
|
||||||
|
|
||||||
_transform(p, ndiv2, k);
|
_transform(p, ndiv2, k);
|
||||||
_transform(p, ndiv2, k + ndiv2);
|
_transform(p, ndiv2, k + ndiv2);
|
||||||
|
|
||||||
j = m_num / ndiv2 - 1;
|
j = num_ / ndiv2 - 1;
|
||||||
t1 = m_buf;
|
t1 = buf_();
|
||||||
t2 = t1 + ndiv2;
|
t2 = t1 + ndiv2;
|
||||||
t3 = p + k + ndiv2;
|
t3 = p + k + ndiv2;
|
||||||
ptab = m_tab;
|
ptab = tab_();
|
||||||
pp = p + k;
|
pp = p + k;
|
||||||
|
|
||||||
a = *ptab++ * *t3++;
|
a = *ptab++ * *t3++;
|
||||||
@@ -200,5 +201,7 @@ void FHT::_transform(float* p, int n, int k) {
|
|||||||
*t1++ = *pp + a;
|
*t1++ = *pp + a;
|
||||||
*t2++ = *pp++ - a;
|
*t2++ = *pp++ - a;
|
||||||
}
|
}
|
||||||
memcpy(p + k, m_buf, sizeof(float) * n);
|
|
||||||
|
std::copy(buf_(), buf_() + n, p + k);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
// FHT - Fast Hartley Transform Class
|
/*
|
||||||
//
|
Strawberry Music Player
|
||||||
// Copyright (C) 2004 Melchior FRANZ - mfranz@kde.org
|
This file was part of Clementine.
|
||||||
//
|
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
|
||||||
// This program is free software; you can redistribute it and/or
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
// modify it under the terms of the GNU General Public License as
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
Copyright 2017, Santiago Gil
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
Strawberry is free software: you can redistribute it and/or modify
|
||||||
// This program is distributed in the hope that it will be useful, but
|
it under the terms of the GNU General Public License as published by
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
(at your option) any later version.
|
||||||
// General Public License for more details.
|
|
||||||
//
|
Strawberry is distributed in the hope that it will be useful,
|
||||||
// You should have received a copy of the GNU General Public License
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// along with this program; if not, write to the Free Software
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA
|
GNU General Public License for more details.
|
||||||
//
|
|
||||||
// $Id$
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef FHT_H
|
#ifndef FHT_H
|
||||||
#define FHT_H
|
#define FHT_H
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Hartley Transform after Bracewell's discrete
|
* Implementation of the Hartley Transform after Bracewell's discrete
|
||||||
* algorithm. The algorithm is subject to US patent No. 4,646,256 (1987)
|
* algorithm. The algorithm is subject to US patent No. 4,646,256 (1987)
|
||||||
@@ -30,11 +34,16 @@
|
|||||||
* [1] Computer in Physics, Vol. 9, No. 4, Jul/Aug 1995 pp 373-379
|
* [1] Computer in Physics, Vol. 9, No. 4, Jul/Aug 1995 pp 373-379
|
||||||
*/
|
*/
|
||||||
class FHT {
|
class FHT {
|
||||||
int m_exp2;
|
const int num_;
|
||||||
int m_num;
|
const int exp2_;
|
||||||
float* m_buf;
|
|
||||||
float* m_tab;
|
QVector<float> buf_vector_;
|
||||||
int* m_log;
|
QVector<float> tab_vector_;
|
||||||
|
QVector<int> log_vector_;
|
||||||
|
|
||||||
|
float* buf_();
|
||||||
|
float* tab_();
|
||||||
|
int* log_();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a table of "cas" (cosine and sine) values.
|
* Create a table of "cas" (cosine and sine) values.
|
||||||
@@ -57,10 +66,8 @@ class FHT {
|
|||||||
FHT(int);
|
FHT(int);
|
||||||
|
|
||||||
~FHT();
|
~FHT();
|
||||||
inline int sizeExp() const { return m_exp2; }
|
int sizeExp() const;
|
||||||
inline int size() const { return m_num; }
|
int size() const;
|
||||||
float* copy(float*, float*);
|
|
||||||
float* clear(float*);
|
|
||||||
void scale(float*, float);
|
void scale(float*, float);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,4 +122,4 @@ class FHT {
|
|||||||
void transform(float*);
|
void transform(float*);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // FHT_H
|
||||||
|
|||||||
207
src/analyzer/rainbowanalyzer.cpp
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
Strawberry Music Player
|
||||||
|
This file was part of Clementine.
|
||||||
|
Copyright 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
||||||
|
Copyright 2011-2012, 2014, David Sansome <me@davidsansome.com>
|
||||||
|
Copyright 2011, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||||
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
Copyright 2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rainbowanalyzer.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QTimerEvent>
|
||||||
|
|
||||||
|
#include "core/arraysize.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
|
using Analyzer::Scope;
|
||||||
|
|
||||||
|
const int Rainbow::RainbowAnalyzer::kHeight[] = {21, 33};
|
||||||
|
const int Rainbow::RainbowAnalyzer::kWidth[] = {34, 53};
|
||||||
|
const int Rainbow::RainbowAnalyzer::kFrameCount[] = {6, 16};
|
||||||
|
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = {21, 16};
|
||||||
|
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = {13, 15};
|
||||||
|
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = {24, 33};
|
||||||
|
|
||||||
|
const char* Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat";
|
||||||
|
const char* Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash";
|
||||||
|
const float Rainbow::RainbowAnalyzer::kPixelScale = 0.02f;
|
||||||
|
|
||||||
|
Rainbow::RainbowAnalyzer::RainbowType Rainbow::RainbowAnalyzer::rainbowtype;
|
||||||
|
|
||||||
|
Rainbow::RainbowAnalyzer::RainbowAnalyzer(const RainbowType& rbtype, QWidget* parent)
|
||||||
|
: Analyzer::Base(parent, 9),
|
||||||
|
timer_id_(startTimer(kFrameIntervalMs)),
|
||||||
|
frame_(0),
|
||||||
|
current_buffer_(0),
|
||||||
|
available_rainbow_width_(0),
|
||||||
|
px_per_frame_(0),
|
||||||
|
x_offset_(0),
|
||||||
|
background_brush_(QColor(0x0f, 0x43, 0x73))
|
||||||
|
{
|
||||||
|
|
||||||
|
rainbowtype = rbtype;
|
||||||
|
cat_dash_[0] = QPixmap(":/pictures/nyancat.png");
|
||||||
|
cat_dash_[1] = QPixmap(":/pictures/rainbowdash.png");
|
||||||
|
memset(history_, 0, sizeof(history_));
|
||||||
|
|
||||||
|
for (int i = 0; i < kRainbowBands; ++i) {
|
||||||
|
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255), kRainbowHeight[rainbowtype] / kRainbowBands, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin);
|
||||||
|
|
||||||
|
// pow constants computed so that
|
||||||
|
// | band_scale(0) | ~= .5 and | band_scale(5) | ~= 32
|
||||||
|
band_scale_[i] = -std::cos(M_PI * i / (kRainbowBands - 1)) * 0.5 * std::pow(2.3, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rainbow::RainbowAnalyzer::transform(Scope& s) { fht_->spectrum(s.data()); }
|
||||||
|
|
||||||
|
void Rainbow::RainbowAnalyzer::timerEvent(QTimerEvent* e) {
|
||||||
|
|
||||||
|
if (e->timerId() == timer_id_) {
|
||||||
|
frame_ = (frame_ + 1) % kFrameCount[rainbowtype];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Analyzer::Base::timerEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rainbow::RainbowAnalyzer::resizeEvent(QResizeEvent* e) {
|
||||||
|
|
||||||
|
// Invalidate the buffer so it's recreated from scratch in the next paint event.
|
||||||
|
buffer_[0] = QPixmap();
|
||||||
|
buffer_[1] = QPixmap();
|
||||||
|
|
||||||
|
available_rainbow_width_ = width() - kWidth[rainbowtype] + kRainbowOverlap[rainbowtype];
|
||||||
|
px_per_frame_ = static_cast<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
|
||||||
|
x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_frame) {
|
||||||
|
|
||||||
|
// Discard the second half of the transform
|
||||||
|
const int scope_size = s.size() / 2;
|
||||||
|
|
||||||
|
if ((new_frame && is_playing_) || (buffer_[0].isNull() && buffer_[1].isNull())) {
|
||||||
|
// Transform the music into rainbows!
|
||||||
|
for (int band = 0; band < kRainbowBands; ++band) {
|
||||||
|
float* band_start = history_ + band * kHistorySize;
|
||||||
|
|
||||||
|
// Move the history of each band across by 1 frame.
|
||||||
|
memmove(band_start, band_start + 1, (kHistorySize - 1) * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now accumulate the scope data into each band. Should maybe use a series
|
||||||
|
// of band pass filters for this, so bands can leak into neighbouring bands,
|
||||||
|
// but for now it's a series of separate square filters.
|
||||||
|
const int samples_per_band = scope_size / kRainbowBands;
|
||||||
|
int sample = 0;
|
||||||
|
for (int band = 0; band < kRainbowBands; ++band) {
|
||||||
|
float accumulator = 0.0;
|
||||||
|
for (int i = 0; i < samples_per_band; ++i) {
|
||||||
|
accumulator += s[sample++];
|
||||||
|
}
|
||||||
|
|
||||||
|
history_[(band + 1) * kHistorySize - 1] = accumulator * band_scale_[band];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create polylines for the rainbows.
|
||||||
|
QPointF polyline[kRainbowBands * kHistorySize];
|
||||||
|
QPointF* dest = polyline;
|
||||||
|
float* source = history_;
|
||||||
|
|
||||||
|
const float top_of = static_cast<float>(height()) / 2 - static_cast<float>(kRainbowHeight[rainbowtype]) / 2;
|
||||||
|
for (int band = 0; band < kRainbowBands; ++band) {
|
||||||
|
// Calculate the Y position of this band.
|
||||||
|
const float y = static_cast<float>(kRainbowHeight[rainbowtype]) / (kRainbowBands + 1) * (band + 0.5) + top_of;
|
||||||
|
|
||||||
|
// Add each point in the line.
|
||||||
|
for (int x = 0; x < kHistorySize; ++x) {
|
||||||
|
*dest = QPointF(px_per_frame_ * x, y + *source * kPixelScale);
|
||||||
|
++dest;
|
||||||
|
++source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have to draw the whole rainbow into the buffer?
|
||||||
|
if (buffer_[0].isNull()) {
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
buffer_[i] = QPixmap(QSize(width() + x_offset_, height()));
|
||||||
|
buffer_[i].fill(background_brush_.color());
|
||||||
|
}
|
||||||
|
current_buffer_ = 0;
|
||||||
|
|
||||||
|
QPainter buffer_painter(&buffer_[0]);
|
||||||
|
buffer_painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
for (int band = kRainbowBands - 1; band >= 0; --band) {
|
||||||
|
buffer_painter.setPen(colors_[band]);
|
||||||
|
buffer_painter.drawPolyline(&polyline[band * kHistorySize], kHistorySize);
|
||||||
|
buffer_painter.drawPolyline(&polyline[band * kHistorySize], kHistorySize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const int last_buffer = current_buffer_;
|
||||||
|
current_buffer_ = (current_buffer_ + 1) % 2;
|
||||||
|
|
||||||
|
// We can just shuffle the buffer along a bit and draw the new frame's data.
|
||||||
|
QPainter buffer_painter(&buffer_[current_buffer_]);
|
||||||
|
buffer_painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
buffer_painter.drawPixmap(0, 0, buffer_[last_buffer], px_per_frame_, 0, x_offset_ + available_rainbow_width_ - px_per_frame_, 0);
|
||||||
|
buffer_painter.fillRect(x_offset_ + available_rainbow_width_ - px_per_frame_, 0, kWidth[rainbowtype] - kRainbowOverlap[rainbowtype] + px_per_frame_, height(), background_brush_);
|
||||||
|
|
||||||
|
for (int band = kRainbowBands - 1; band >= 0; --band) {
|
||||||
|
buffer_painter.setPen(colors_[band]);
|
||||||
|
buffer_painter.drawPolyline(&polyline[(band + 1) * kHistorySize - 3], 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the buffer on to the widget
|
||||||
|
p.drawPixmap(0, 0, buffer_[current_buffer_], x_offset_, 0, 0, 0);
|
||||||
|
|
||||||
|
// Draw rainbow analyzer (nyan cat or rainbowdash)
|
||||||
|
// Nyan nyan nyan nyan dash dash dash dash.
|
||||||
|
if (!is_playing_) {
|
||||||
|
// Ssshhh!
|
||||||
|
p.drawPixmap(SleepingDestRect(rainbowtype), cat_dash_[rainbowtype], SleepingSourceRect(rainbowtype));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.drawPixmap(DestRect(rainbowtype), cat_dash_[rainbowtype], SourceRect(rainbowtype));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rainbow::NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
|
||||||
|
: RainbowAnalyzer(Rainbow::RainbowAnalyzer::Nyancat, parent) {}
|
||||||
|
|
||||||
|
Rainbow::RainbowDashAnalyzer::RainbowDashAnalyzer(QWidget* parent)
|
||||||
|
: RainbowAnalyzer(Rainbow::RainbowAnalyzer::Dash, parent) {}
|
||||||
141
src/analyzer/rainbowanalyzer.h
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
Strawberry Music Player
|
||||||
|
This file was part of Clementine.
|
||||||
|
Copyright 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
||||||
|
Copyright 2011-2012, 2014, David Sansome <me@davidsansome.com>
|
||||||
|
Copyright 2011, 2014, John Maguire <john.maguire@gmail.com>
|
||||||
|
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||||
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||||
|
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||||
|
Copyright 2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RAINBOWANALYZER_H
|
||||||
|
#define RAINBOWANALYZER_H
|
||||||
|
|
||||||
|
#include "analyzerbase.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPen>
|
||||||
|
|
||||||
|
namespace Rainbow {
|
||||||
|
class RainbowAnalyzer : public Analyzer::Base {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum RainbowType {
|
||||||
|
Nyancat = 0,
|
||||||
|
Dash = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
RainbowAnalyzer(const RainbowType& rbtype, QWidget* parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void transform(Analyzer::Scope&);
|
||||||
|
void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
|
||||||
|
|
||||||
|
void timerEvent(QTimerEvent* e);
|
||||||
|
void resizeEvent(QResizeEvent* e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int kHeight[];
|
||||||
|
static const int kWidth[];
|
||||||
|
static const int kFrameCount[];
|
||||||
|
static const int kRainbowHeight[];
|
||||||
|
static const int kRainbowOverlap[];
|
||||||
|
static const int kSleepingHeight[];
|
||||||
|
|
||||||
|
static const int kHistorySize = 128;
|
||||||
|
static const int kRainbowBands = 6;
|
||||||
|
static const float kPixelScale;
|
||||||
|
|
||||||
|
static const int kFrameIntervalMs = 150;
|
||||||
|
|
||||||
|
static RainbowType rainbowtype;
|
||||||
|
|
||||||
|
inline QRect SourceRect(RainbowType rainbowtype) const {
|
||||||
|
return QRect(0, kHeight[rainbowtype] * frame_, kWidth[rainbowtype], kHeight[rainbowtype]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QRect SleepingSourceRect(RainbowType rainbowtype) const {
|
||||||
|
return QRect(0, kHeight[rainbowtype] * kFrameCount[rainbowtype], kWidth[rainbowtype], kSleepingHeight[rainbowtype]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QRect DestRect(RainbowType rainbowtype) const {
|
||||||
|
return QRect(width() - kWidth[rainbowtype], (height() - kHeight[rainbowtype]) / 2, kWidth[rainbowtype], kHeight[rainbowtype]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QRect SleepingDestRect(RainbowType rainbowtype) const {
|
||||||
|
return QRect(width() - kWidth[rainbowtype], (height() - kSleepingHeight[rainbowtype]) / 2, kWidth[rainbowtype], kSleepingHeight[rainbowtype]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// "constants" that get initialised in the constructor
|
||||||
|
float band_scale_[kRainbowBands];
|
||||||
|
QPen colors_[kRainbowBands];
|
||||||
|
|
||||||
|
// Rainbow Nyancat & Dash
|
||||||
|
QPixmap cat_dash_[2];
|
||||||
|
|
||||||
|
// For the cat or dash animation
|
||||||
|
int timer_id_;
|
||||||
|
int frame_;
|
||||||
|
|
||||||
|
// The y positions of each point on the rainbow.
|
||||||
|
float history_[kHistorySize * kRainbowBands];
|
||||||
|
|
||||||
|
// A cache of the last frame's rainbow,
|
||||||
|
// so it can be used in the next frame.
|
||||||
|
QPixmap buffer_[2];
|
||||||
|
int current_buffer_;
|
||||||
|
|
||||||
|
// Geometry information that's updated on resize:
|
||||||
|
// The width of the widget minus the space for the cat
|
||||||
|
int available_rainbow_width_;
|
||||||
|
|
||||||
|
// X spacing between each point in the polyline.
|
||||||
|
int px_per_frame_;
|
||||||
|
|
||||||
|
// Amount the buffer_ is shifted to the left (off the edge of the widget)
|
||||||
|
// to make the rainbow extend from 0 to available_rainbow_width_.
|
||||||
|
int x_offset_;
|
||||||
|
|
||||||
|
QBrush background_brush_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NyanCatAnalyzer : public RainbowAnalyzer {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE NyanCatAnalyzer(QWidget* parent);
|
||||||
|
|
||||||
|
static const char* kName;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RainbowDashAnalyzer : public RainbowAnalyzer {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE RainbowDashAnalyzer(QWidget* parent);
|
||||||
|
|
||||||
|
static const char* kName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // RAINBOWANALYZER_H
|
||||||
@@ -63,6 +63,7 @@ SCollection::SCollection(Application *app, QObject *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SCollection::~SCollection() {
|
SCollection::~SCollection() {
|
||||||
|
watcher_->Stop();
|
||||||
watcher_->deleteLater();
|
watcher_->deleteLater();
|
||||||
watcher_thread_->exit();
|
watcher_thread_->exit();
|
||||||
watcher_thread_->wait(5000 /* five seconds */);
|
watcher_thread_->wait(5000 /* five seconds */);
|
||||||
|
|||||||
@@ -323,6 +323,17 @@ SongList CollectionBackend::FindSongsInDirectory(int id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionBackend::SongPathChanged(const Song &song, const QFileInfo &new_file) {
|
||||||
|
|
||||||
|
// Take a song and update its path
|
||||||
|
Song updated_song = song;
|
||||||
|
updated_song.InitFromFilePartial(new_file.absoluteFilePath());
|
||||||
|
SongList updated_songs;
|
||||||
|
updated_songs << updated_song;
|
||||||
|
AddOrUpdateSongs(updated_songs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionBackend::AddOrUpdateSubdirs(const SubdirectoryList &subdirs) {
|
void CollectionBackend::AddOrUpdateSubdirs(const SubdirectoryList &subdirs) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
@@ -575,10 +586,8 @@ QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QStringList ret;
|
|
||||||
QSet<QString> artists;
|
QSet<QString> artists;
|
||||||
while (query.Next()) {
|
while (query.Next()) {
|
||||||
//ret << query.Value(0).toString();
|
|
||||||
artists << query.Value(0).toString();
|
artists << query.Value(0).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,8 +595,8 @@ QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt)
|
|||||||
artists << query2.Value(0).toString();
|
artists << query2.Value(0).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// return ret;
|
|
||||||
return QStringList(artists.toList());
|
return QStringList(artists.toList());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetAllAlbums(const QueryOptions &opt) {
|
||||||
@@ -659,6 +668,7 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QString &table, const QString &column) {
|
SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QString &table, const QString &column) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
@@ -678,6 +688,7 @@ SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QS
|
|||||||
ret[index].InitFromQuery(q, true);
|
ret[index].InitFromQuery(q, true);
|
||||||
}
|
}
|
||||||
return ret.toList();
|
return ret.toList();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Song CollectionBackend::GetSongById(int id, QSqlDatabase &db) {
|
Song CollectionBackend::GetSongById(int id, QSqlDatabase &db) {
|
||||||
@@ -687,6 +698,7 @@ Song CollectionBackend::GetSongById(int id, QSqlDatabase &db) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &db) {
|
SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &db) {
|
||||||
|
|
||||||
QString in = ids.join(",");
|
QString in = ids.join(",");
|
||||||
|
|
||||||
QSqlQuery q(db);
|
QSqlQuery q(db);
|
||||||
@@ -701,12 +713,14 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &d
|
|||||||
ret << song;
|
ret << song;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
|
Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
|
||||||
|
|
||||||
CollectionQuery query;
|
CollectionQuery query;
|
||||||
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||||
query.AddWhere("filename", url.toEncoded());
|
query.AddWhere("filename", url.toString());
|
||||||
query.AddWhere("beginning", beginning);
|
query.AddWhere("beginning", beginning);
|
||||||
|
|
||||||
Song song;
|
Song song;
|
||||||
@@ -714,12 +728,14 @@ Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
|
|||||||
song.InitFromQuery(query, true);
|
song.InitFromQuery(query, true);
|
||||||
}
|
}
|
||||||
return song;
|
return song;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
|
SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
|
||||||
|
|
||||||
CollectionQuery query;
|
CollectionQuery query;
|
||||||
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||||
query.AddWhere("filename", url.toEncoded());
|
query.AddWhere("filename", url.toString());
|
||||||
|
|
||||||
SongList songlist;
|
SongList songlist;
|
||||||
if (ExecQuery(&query)) {
|
if (ExecQuery(&query)) {
|
||||||
@@ -730,6 +746,7 @@ SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return songlist;
|
return songlist;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const QueryOptions &opt) {
|
CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const QueryOptions &opt) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@@ -194,6 +195,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
|||||||
void IncrementPlayCount(int id);
|
void IncrementPlayCount(int id);
|
||||||
void IncrementSkipCount(int id, float progress);
|
void IncrementSkipCount(int id, float progress);
|
||||||
void ResetStatistics(int id);
|
void ResetStatistics(int id);
|
||||||
|
void SongPathChanged(const Song &song, const QFileInfo &new_file);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void DirectoryDiscovered(const Directory &dir, const SubdirectoryList &subdirs);
|
void DirectoryDiscovered(const Directory &dir, const SubdirectoryList &subdirs);
|
||||||
|
|||||||
@@ -149,13 +149,13 @@ void CollectionFilterWidget::UpdateGroupByActions() {
|
|||||||
QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
|
QActionGroup *CollectionFilterWidget::CreateGroupByActions(QObject *parent) {
|
||||||
|
|
||||||
QActionGroup *ret = new QActionGroup(parent);
|
QActionGroup *ret = new QActionGroup(parent);
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Artist"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist)));
|
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_Album)));
|
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Album artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_Album)));
|
ret->addAction(CreateGroupByAction(tr("Group by Album artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_AlbumArtist, CollectionModel::GroupBy_Album)));
|
||||||
|
ret->addAction(CreateGroupByAction(tr("Group by Artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_Album)));
|
||||||
|
ret->addAction(CreateGroupByAction(tr("Group by Genre/Artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Genre, CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_Album)));
|
||||||
|
ret->addAction(CreateGroupByAction(tr("Group by Artist"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist)));
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Artist/Year - Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_YearAlbum)));
|
ret->addAction(CreateGroupByAction(tr("Group by Artist/Year - Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_YearAlbum)));
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Album)));
|
ret->addAction(CreateGroupByAction(tr("Group by Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Album)));
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Genre/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Genre, CollectionModel::GroupBy_Album)));
|
ret->addAction(CreateGroupByAction(tr("Group by Genre/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Genre, CollectionModel::GroupBy_Album)));
|
||||||
ret->addAction(CreateGroupByAction(tr("Group by Genre/Artist/Album"), parent, CollectionModel::Grouping(CollectionModel::GroupBy_Genre, CollectionModel::GroupBy_Artist, CollectionModel::GroupBy_Album)));
|
|
||||||
|
|
||||||
QAction *sep1 = new QAction(parent);
|
QAction *sep1 = new QAction(parent);
|
||||||
sep1->setSeparator(true);
|
sep1->setSeparator(true);
|
||||||
|
|||||||
@@ -94,8 +94,7 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
|
|||||||
playlist_icon_(IconLoader::Load("albums")),
|
playlist_icon_(IconLoader::Load("albums")),
|
||||||
init_task_id_(-1),
|
init_task_id_(-1),
|
||||||
use_pretty_covers_(false),
|
use_pretty_covers_(false),
|
||||||
show_dividers_(true)
|
show_dividers_(true) {
|
||||||
{
|
|
||||||
|
|
||||||
root_->lazy_loaded = true;
|
root_->lazy_loaded = true;
|
||||||
|
|
||||||
@@ -212,14 +211,14 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
|||||||
// Otherwise find the proper container at this level based on the item's key
|
// Otherwise find the proper container at this level based on the item's key
|
||||||
QString key;
|
QString key;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GroupBy_Album: key = song.album(); break;
|
case GroupBy_AlbumArtist: key = song.effective_albumartist(); break;
|
||||||
case GroupBy_Artist: key = song.artist(); break;
|
case GroupBy_Artist: key = song.artist(); break;
|
||||||
|
case GroupBy_Album: key = song.album(); break;
|
||||||
case GroupBy_Composer: key = song.composer(); break;
|
case GroupBy_Composer: key = song.composer(); break;
|
||||||
case GroupBy_Performer: key = song.performer(); break;
|
case GroupBy_Performer: key = song.performer(); break;
|
||||||
case GroupBy_Disc: key = QString::number(song.disc()); break;
|
|
||||||
case GroupBy_Grouping: key = song.grouping(); break;
|
case GroupBy_Grouping: key = song.grouping(); break;
|
||||||
|
case GroupBy_Disc: key = QString::number(song.disc()); break;
|
||||||
case GroupBy_Genre: key = song.genre(); break;
|
case GroupBy_Genre: key = song.genre(); break;
|
||||||
case GroupBy_AlbumArtist: key = song.effective_albumartist(); break;
|
|
||||||
case GroupBy_Year:
|
case GroupBy_Year:
|
||||||
key = QString::number(qMax(0, song.year()));
|
key = QString::number(qMax(0, song.year()));
|
||||||
break;
|
break;
|
||||||
@@ -233,16 +232,29 @@ void CollectionModel::SongsDiscovered(const SongList &songs) {
|
|||||||
key = PrettyYearAlbum(qMax(0, song.effective_originalyear()), song.album());
|
key = PrettyYearAlbum(qMax(0, song.effective_originalyear()), song.album());
|
||||||
break;
|
break;
|
||||||
case GroupBy_FileType:
|
case GroupBy_FileType:
|
||||||
key = song.filetype();
|
key = QString::number(song.filetype());
|
||||||
break;
|
|
||||||
case GroupBy_Bitrate:
|
|
||||||
key = song.bitrate();
|
|
||||||
break;
|
break;
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:
|
||||||
key = song.samplerate();
|
key = QString::number(song.samplerate());
|
||||||
break;
|
break;
|
||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:
|
||||||
key = song.bitdepth();
|
key = QString::number(song.bitdepth());
|
||||||
|
break;
|
||||||
|
case GroupBy_Bitrate:
|
||||||
|
key = QString::number(song.bitrate());
|
||||||
|
break;
|
||||||
|
case GroupBy_Format:
|
||||||
|
if (song.samplerate() <= 0) {
|
||||||
|
key = QString::number(song.filetype());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (song.bitdepth() <= 0) {
|
||||||
|
key = QString("%1 (%2)").arg(song.filetype()).arg(QString::number(song.samplerate() / 1000.0, 'G', 5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key = QString("%1 (%2/%3)").arg(song.filetype()).arg(QString::number(song.samplerate() / 1000.0, 'G', 5)).arg(song.bitdepth());
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
qLog(Error) << "GroupBy_None";
|
qLog(Error) << "GroupBy_None";
|
||||||
@@ -303,22 +315,23 @@ QString CollectionModel::DividerKey(GroupBy type, CollectionItem *item) const {
|
|||||||
if (item->sort_text.isEmpty()) return QString();
|
if (item->sort_text.isEmpty()) return QString();
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GroupBy_Album:
|
case GroupBy_AlbumArtist:
|
||||||
case GroupBy_Artist:
|
case GroupBy_Artist:
|
||||||
|
case GroupBy_Album:
|
||||||
case GroupBy_Composer:
|
case GroupBy_Composer:
|
||||||
case GroupBy_Performer:
|
case GroupBy_Performer:
|
||||||
case GroupBy_Disc:
|
|
||||||
case GroupBy_Grouping:
|
case GroupBy_Grouping:
|
||||||
|
case GroupBy_Disc:
|
||||||
case GroupBy_Genre:
|
case GroupBy_Genre:
|
||||||
case GroupBy_AlbumArtist:
|
case GroupBy_Format:
|
||||||
case GroupBy_FileType: {
|
case GroupBy_FileType: {
|
||||||
QChar c = item->sort_text[0];
|
QChar c = item->sort_text[0];
|
||||||
if (c.isDigit()) return "0";
|
if (c.isDigit()) return "0";
|
||||||
if (c == ' ') return QString();
|
if (c == ' ') return QString();
|
||||||
if (c.decompositionTag() != QChar::NoDecomposition)
|
if (c.decompositionTag() != QChar::NoDecomposition)
|
||||||
return QChar(c.decomposition()[0]);
|
return QChar(c.decomposition()[0]);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
case GroupBy_Year:
|
case GroupBy_Year:
|
||||||
case GroupBy_OriginalYear:
|
case GroupBy_OriginalYear:
|
||||||
@@ -330,15 +343,15 @@ QString CollectionModel::DividerKey(GroupBy type, CollectionItem *item) const {
|
|||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_OriginalYearAlbum:
|
||||||
return SortTextForNumber(item->metadata.effective_originalyear());
|
return SortTextForNumber(item->metadata.effective_originalyear());
|
||||||
|
|
||||||
case GroupBy_Bitrate:
|
|
||||||
return SortTextForNumber(item->metadata.bitrate());
|
|
||||||
|
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:
|
||||||
return SortTextForNumber(item->metadata.samplerate());
|
return SortTextForNumber(item->metadata.samplerate());
|
||||||
|
|
||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:
|
||||||
return SortTextForNumber(item->metadata.bitdepth());
|
return SortTextForNumber(item->metadata.bitdepth());
|
||||||
|
|
||||||
|
case GroupBy_Bitrate:
|
||||||
|
return SortTextForNumber(item->metadata.bitrate());
|
||||||
|
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -361,6 +374,7 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
|
|||||||
case GroupBy_Genre:
|
case GroupBy_Genre:
|
||||||
case GroupBy_AlbumArtist:
|
case GroupBy_AlbumArtist:
|
||||||
case GroupBy_FileType:
|
case GroupBy_FileType:
|
||||||
|
case GroupBy_Format:
|
||||||
if (key == "0") return "0-9";
|
if (key == "0") return "0-9";
|
||||||
return key.toUpper();
|
return key.toUpper();
|
||||||
|
|
||||||
@@ -374,10 +388,6 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
|
|||||||
if (key == "0000") return tr("Unknown");
|
if (key == "0000") return tr("Unknown");
|
||||||
return QString::number(key.toInt()); // To remove leading 0s
|
return QString::number(key.toInt()); // To remove leading 0s
|
||||||
|
|
||||||
case GroupBy_Bitrate:
|
|
||||||
if (key == "000") return tr("Unknown");
|
|
||||||
return QString::number(key.toInt()); // To remove leading 0s
|
|
||||||
|
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:
|
||||||
if (key == "000") return tr("Unknown");
|
if (key == "000") return tr("Unknown");
|
||||||
return QString::number(key.toInt()); // To remove leading 0s
|
return QString::number(key.toInt()); // To remove leading 0s
|
||||||
@@ -386,6 +396,10 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
|
|||||||
if (key == "000") return tr("Unknown");
|
if (key == "000") return tr("Unknown");
|
||||||
return QString::number(key.toInt()); // To remove leading 0s
|
return QString::number(key.toInt()); // To remove leading 0s
|
||||||
|
|
||||||
|
case GroupBy_Bitrate:
|
||||||
|
if (key == "000") return tr("Unknown");
|
||||||
|
return QString::number(key.toInt()); // To remove leading 0s
|
||||||
|
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
// fallthrough
|
// fallthrough
|
||||||
;
|
;
|
||||||
@@ -753,6 +767,7 @@ void CollectionModel::PostQuery(CollectionItem *parent, const CollectionModel::Q
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CollectionModel::LazyPopulate(CollectionItem *parent, bool signal) {
|
void CollectionModel::LazyPopulate(CollectionItem *parent, bool signal) {
|
||||||
|
|
||||||
if (parent->lazy_loaded) return;
|
if (parent->lazy_loaded) return;
|
||||||
parent->lazy_loaded = true;
|
parent->lazy_loaded = true;
|
||||||
|
|
||||||
@@ -817,6 +832,9 @@ void CollectionModel::InitQuery(GroupBy type, CollectionQuery *q) {
|
|||||||
|
|
||||||
// Say what type of thing we want to get back from the database.
|
// Say what type of thing we want to get back from the database.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case GroupBy_AlbumArtist:
|
||||||
|
q->SetColumnSpec("DISTINCT effective_albumartist");
|
||||||
|
break;
|
||||||
case GroupBy_Artist:
|
case GroupBy_Artist:
|
||||||
q->SetColumnSpec("DISTINCT artist");
|
q->SetColumnSpec("DISTINCT artist");
|
||||||
break;
|
break;
|
||||||
@@ -850,11 +868,8 @@ void CollectionModel::InitQuery(GroupBy type, CollectionQuery *q) {
|
|||||||
case GroupBy_Genre:
|
case GroupBy_Genre:
|
||||||
q->SetColumnSpec("DISTINCT genre");
|
q->SetColumnSpec("DISTINCT genre");
|
||||||
break;
|
break;
|
||||||
case GroupBy_AlbumArtist:
|
case GroupBy_FileType:
|
||||||
q->SetColumnSpec("DISTINCT effective_albumartist");
|
q->SetColumnSpec("DISTINCT filetype");
|
||||||
break;
|
|
||||||
case GroupBy_Bitrate:
|
|
||||||
q->SetColumnSpec("DISTINCT bitrate");
|
|
||||||
break;
|
break;
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:
|
||||||
q->SetColumnSpec("DISTINCT samplerate");
|
q->SetColumnSpec("DISTINCT samplerate");
|
||||||
@@ -862,12 +877,15 @@ void CollectionModel::InitQuery(GroupBy type, CollectionQuery *q) {
|
|||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:
|
||||||
q->SetColumnSpec("DISTINCT bitdepth");
|
q->SetColumnSpec("DISTINCT bitdepth");
|
||||||
break;
|
break;
|
||||||
|
case GroupBy_Bitrate:
|
||||||
|
q->SetColumnSpec("DISTINCT bitrate");
|
||||||
|
break;
|
||||||
|
case GroupBy_Format:
|
||||||
|
q->SetColumnSpec("DISTINCT filetype, samplerate, bitdepth");
|
||||||
|
break;
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
q->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
q->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||||
break;
|
break;
|
||||||
case GroupBy_FileType:
|
|
||||||
q->SetColumnSpec("DISTINCT filetype");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -877,6 +895,15 @@ void CollectionModel::FilterQuery(GroupBy type, CollectionItem *item, Collection
|
|||||||
// Say how we want the query to be filtered. This is done once for each parent going up the tree.
|
// Say how we want the query to be filtered. This is done once for each parent going up the tree.
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case GroupBy_AlbumArtist:
|
||||||
|
if (IsCompilationArtistNode(item))
|
||||||
|
q->AddCompilationRequirement(true);
|
||||||
|
else {
|
||||||
|
// Don't duplicate compilations outside the Various artists node
|
||||||
|
q->AddCompilationRequirement(false);
|
||||||
|
q->AddWhere("effective_albumartist", item->key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GroupBy_Artist:
|
case GroupBy_Artist:
|
||||||
if (IsCompilationArtistNode(item))
|
if (IsCompilationArtistNode(item))
|
||||||
q->AddCompilationRequirement(true);
|
q->AddCompilationRequirement(true);
|
||||||
@@ -922,27 +949,23 @@ void CollectionModel::FilterQuery(GroupBy type, CollectionItem *item, Collection
|
|||||||
case GroupBy_Genre:
|
case GroupBy_Genre:
|
||||||
q->AddWhere("genre", item->key);
|
q->AddWhere("genre", item->key);
|
||||||
break;
|
break;
|
||||||
case GroupBy_AlbumArtist:
|
|
||||||
if (IsCompilationArtistNode(item))
|
|
||||||
q->AddCompilationRequirement(true);
|
|
||||||
else {
|
|
||||||
// Don't duplicate compilations outside the Various artists node
|
|
||||||
q->AddCompilationRequirement(false);
|
|
||||||
q->AddWhere("effective_albumartist", item->key);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GroupBy_FileType:
|
case GroupBy_FileType:
|
||||||
q->AddWhere("filetype", item->metadata.filetype());
|
q->AddWhere("filetype", item->metadata.filetype());
|
||||||
break;
|
break;
|
||||||
case GroupBy_Bitrate:
|
|
||||||
q->AddWhere("bitrate", item->key);
|
|
||||||
break;
|
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:
|
||||||
q->AddWhere("samplerate", item->key);
|
q->AddWhere("samplerate", item->key);
|
||||||
break;
|
break;
|
||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:
|
||||||
q->AddWhere("bitdepth", item->key);
|
q->AddWhere("bitdepth", item->key);
|
||||||
break;
|
break;
|
||||||
|
case GroupBy_Bitrate:
|
||||||
|
q->AddWhere("bitrate", item->key);
|
||||||
|
break;
|
||||||
|
case GroupBy_Format:
|
||||||
|
q->AddWhere("filetype", item->metadata.filetype());
|
||||||
|
q->AddWhere("samplerate", item->metadata.samplerate());
|
||||||
|
q->AddWhere("bitdepth", item->metadata.bitdepth());
|
||||||
|
break;
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
qLog(Error) << "Unknown GroupBy type" << type << "used in filter";
|
qLog(Error) << "Unknown GroupBy type" << type << "used in filter";
|
||||||
break;
|
break;
|
||||||
@@ -968,84 +991,98 @@ CollectionItem *CollectionModel::InitItem(GroupBy type, bool signal, CollectionI
|
|||||||
CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const SqlRow &row, int container_level) {
|
CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const SqlRow &row, int container_level) {
|
||||||
|
|
||||||
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
||||||
int year(0), effective_originalyear(0), disc(0), bitrate(0), samplerate(0), bitdepth(0);
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case GroupBy_AlbumArtist:
|
||||||
case GroupBy_Artist:
|
case GroupBy_Artist:
|
||||||
|
case GroupBy_Album:
|
||||||
|
case GroupBy_Composer:
|
||||||
|
case GroupBy_Performer:
|
||||||
|
case GroupBy_Grouping:
|
||||||
|
case GroupBy_Genre:
|
||||||
item->key = row.value(0).toString();
|
item->key = row.value(0).toString();
|
||||||
item->display_text = TextOrUnknown(item->key);
|
item->display_text = TextOrUnknown(item->key);
|
||||||
item->sort_text = SortTextForArtist(item->key);
|
item->sort_text = SortTextForArtist(item->key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_OriginalYear:{
|
||||||
year = qMax(0, row.value(0).toInt());
|
int year = qMax(0, row.value(0).toInt());
|
||||||
|
item->key = QString::number(year);
|
||||||
|
item->sort_text = SortTextForNumber(year) + " ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GroupBy_Year:{
|
||||||
|
int year = qMax(0, row.value(0).toInt());
|
||||||
|
item->key = QString::number(year);
|
||||||
|
item->sort_text = SortTextForNumber(year) + " ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GroupBy_OriginalYearAlbum:{
|
||||||
|
item->metadata.set_year(row.value(0).toInt());
|
||||||
|
item->metadata.set_originalyear(row.value(1).toInt());
|
||||||
|
item->metadata.set_album(row.value(2).toString());
|
||||||
|
item->metadata.set_grouping(row.value(3).toString());
|
||||||
|
int effective_originalyear = qMax(0, item->metadata.effective_originalyear());
|
||||||
|
item->key = PrettyYearAlbum(effective_originalyear, item->metadata.album());
|
||||||
|
item->sort_text = SortTextForNumber(effective_originalyear) + item->metadata.grouping() + item->metadata.album();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GroupBy_YearAlbum:{
|
||||||
|
int year = qMax(0, row.value(0).toInt());
|
||||||
item->metadata.set_year(row.value(0).toInt());
|
item->metadata.set_year(row.value(0).toInt());
|
||||||
item->metadata.set_album(row.value(1).toString());
|
item->metadata.set_album(row.value(1).toString());
|
||||||
item->metadata.set_grouping(row.value(2).toString());
|
item->metadata.set_grouping(row.value(2).toString());
|
||||||
item->key = PrettyYearAlbum(year, item->metadata.album());
|
item->key = PrettyYearAlbum(year, item->metadata.album());
|
||||||
item->sort_text = SortTextForNumber(year) + item->metadata.grouping() + item->metadata.album();
|
item->sort_text = SortTextForNumber(year) + item->metadata.grouping() + item->metadata.album();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_Format:{
|
||||||
item->metadata.set_year(row.value(0).toInt());
|
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
|
||||||
item->metadata.set_originalyear(row.value(1).toInt());
|
item->metadata.set_samplerate(row.value(1).toInt());
|
||||||
item->metadata.set_album(row.value(2).toString());
|
item->metadata.set_bitdepth(row.value(2).toInt());
|
||||||
item->metadata.set_grouping(row.value(3).toString());
|
if (item->metadata.samplerate() <= 0) {
|
||||||
effective_originalyear = qMax(0, item->metadata.effective_originalyear());
|
item->key = item->metadata.TextForFiletype();
|
||||||
item->key = PrettyYearAlbum(effective_originalyear, item->metadata.album());
|
}
|
||||||
item->sort_text = SortTextForNumber(effective_originalyear) + item->metadata.grouping() + item->metadata.album();
|
else {
|
||||||
|
if (item->metadata.bitdepth() <= 0) {
|
||||||
|
item->key = QString("%1 (%2)").arg(item->metadata.TextForFiletype()).arg(QString::number(item->metadata.samplerate() / 1000.0, 'G', 5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item->key = QString("%1 (%2/%3)").arg(item->metadata.TextForFiletype()).arg(QString::number(item->metadata.samplerate() / 1000.0, 'G', 5)).arg(QString::number(item->metadata.bitdepth()));
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GroupBy_Year:
|
case GroupBy_Disc:{
|
||||||
year = qMax(0, row.value(0).toInt());
|
int disc = row.value(0).toInt();
|
||||||
item->key = QString::number(year);
|
|
||||||
item->sort_text = SortTextForNumber(year) + " ";
|
|
||||||
break;
|
|
||||||
case GroupBy_OriginalYear:
|
|
||||||
year = qMax(0, row.value(0).toInt());
|
|
||||||
item->key = QString::number(year);
|
|
||||||
item->sort_text = SortTextForNumber(year) + " ";
|
|
||||||
break;
|
|
||||||
case GroupBy_Composer:
|
|
||||||
case GroupBy_Performer:
|
|
||||||
case GroupBy_Grouping:
|
|
||||||
case GroupBy_Genre:
|
|
||||||
case GroupBy_Album:
|
|
||||||
case GroupBy_AlbumArtist:
|
|
||||||
item->key = row.value(0).toString();
|
|
||||||
item->display_text = TextOrUnknown(item->key);
|
|
||||||
item->sort_text = SortTextForArtist(item->key);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GroupBy_Disc:
|
|
||||||
disc = row.value(0).toInt();
|
|
||||||
item->key = QString::number(disc);
|
item->key = QString::number(disc);
|
||||||
item->sort_text = SortTextForNumber(disc);
|
item->sort_text = SortTextForNumber(disc);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_FileType:
|
case GroupBy_FileType:
|
||||||
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
|
item->metadata.set_filetype(Song::FileType(row.value(0).toInt()));
|
||||||
item->key = item->metadata.TextForFiletype();
|
item->key = item->metadata.TextForFiletype();
|
||||||
break;
|
break;
|
||||||
|
case GroupBy_Samplerate:{
|
||||||
case GroupBy_Bitrate:
|
int samplerate = qMax(0, row.value(0).toInt());
|
||||||
bitrate = qMax(0, row.value(0).toInt());
|
|
||||||
item->key = QString::number(bitrate);
|
|
||||||
item->sort_text = SortTextForNumber(bitrate) + " ";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GroupBy_Samplerate:
|
|
||||||
samplerate = qMax(0, row.value(0).toInt());
|
|
||||||
item->key = QString::number(samplerate);
|
item->key = QString::number(samplerate);
|
||||||
item->sort_text = SortTextForNumber(samplerate) + " ";
|
item->sort_text = SortTextForNumber(samplerate) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:{
|
||||||
bitdepth = qMax(0, row.value(0).toInt());
|
int bitdepth = qMax(0, row.value(0).toInt());
|
||||||
item->key = QString::number(bitdepth);
|
item->key = QString::number(bitdepth);
|
||||||
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case GroupBy_Bitrate:{
|
||||||
|
int bitrate = qMax(0, row.value(0).toInt());
|
||||||
|
item->key = QString::number(bitrate);
|
||||||
|
item->sort_text = SortTextForNumber(bitrate) + " ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
item->metadata.InitFromQuery(row, true);
|
item->metadata.InitFromQuery(row, true);
|
||||||
item->key = item->metadata.title();
|
item->key = item->metadata.title();
|
||||||
@@ -1063,7 +1100,6 @@ CollectionItem *CollectionModel::ItemFromQuery(GroupBy type, bool signal, bool c
|
|||||||
CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const Song &s, int container_level) {
|
CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool create_divider, CollectionItem *parent, const Song &s, int container_level) {
|
||||||
|
|
||||||
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
CollectionItem *item = InitItem(type, signal, parent, container_level);
|
||||||
int year(0), originalyear(0), effective_originalyear(0), bitrate(0), samplerate(0), bitdepth(0);
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GroupBy_Artist:
|
case GroupBy_Artist:
|
||||||
@@ -1072,37 +1108,37 @@ CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool cr
|
|||||||
item->sort_text = SortTextForArtist(item->key);
|
item->sort_text = SortTextForArtist(item->key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupBy_YearAlbum:
|
case GroupBy_YearAlbum:{
|
||||||
year = qMax(0, s.year());
|
int year = qMax(0, s.year());
|
||||||
item->metadata.set_year(year);
|
item->metadata.set_year(year);
|
||||||
item->metadata.set_album(s.album());
|
item->metadata.set_album(s.album());
|
||||||
item->key = PrettyYearAlbum(year, s.album());
|
item->key = PrettyYearAlbum(year, s.album());
|
||||||
item->sort_text = SortTextForNumber(year) + s.grouping() + s.album();
|
item->sort_text = SortTextForNumber(year) + s.grouping() + s.album();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_OriginalYearAlbum:
|
case GroupBy_OriginalYearAlbum:{
|
||||||
year = qMax(0, s.year());
|
int year = qMax(0, s.year());
|
||||||
originalyear = qMax(0, s.originalyear());
|
int originalyear = qMax(0, s.originalyear());
|
||||||
effective_originalyear = qMax(0, s.effective_originalyear());
|
int effective_originalyear = qMax(0, s.effective_originalyear());
|
||||||
item->metadata.set_year(year);
|
item->metadata.set_year(year);
|
||||||
item->metadata.set_originalyear(originalyear);
|
item->metadata.set_originalyear(originalyear);
|
||||||
item->metadata.set_album(s.album());
|
item->metadata.set_album(s.album());
|
||||||
item->key = PrettyYearAlbum(effective_originalyear, s.album());
|
item->key = PrettyYearAlbum(effective_originalyear, s.album());
|
||||||
item->sort_text = SortTextForNumber(effective_originalyear) + s.grouping() + s.album();
|
item->sort_text = SortTextForNumber(effective_originalyear) + s.grouping() + s.album();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_Year:
|
case GroupBy_Year:{
|
||||||
year = qMax(0, s.year());
|
int year = qMax(0, s.year());
|
||||||
item->key = QString::number(year);
|
item->key = QString::number(year);
|
||||||
item->sort_text = SortTextForNumber(year) + " ";
|
item->sort_text = SortTextForNumber(year) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_OriginalYear:
|
case GroupBy_OriginalYear:{
|
||||||
year = qMax(0, s.effective_originalyear());
|
int year = qMax(0, s.effective_originalyear());
|
||||||
item->key = QString::number(year);
|
item->key = QString::number(year);
|
||||||
item->sort_text = SortTextForNumber(year) + " ";
|
item->sort_text = SortTextForNumber(year) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_Composer: item->key = s.composer();
|
case GroupBy_Composer: item->key = s.composer();
|
||||||
case GroupBy_Performer: item->key = s.performer();
|
case GroupBy_Performer: item->key = s.performer();
|
||||||
case GroupBy_Grouping: item->key = s.grouping();
|
case GroupBy_Grouping: item->key = s.grouping();
|
||||||
@@ -1123,24 +1159,41 @@ CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool cr
|
|||||||
item->key = s.TextForFiletype();
|
item->key = s.TextForFiletype();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GroupBy_Bitrate:
|
case GroupBy_Bitrate:{
|
||||||
bitrate = qMax(0, s.bitrate());
|
int bitrate = qMax(0, s.bitrate());
|
||||||
item->key = QString::number(bitrate);
|
item->key = QString::number(bitrate);
|
||||||
item->sort_text = SortTextForNumber(bitrate) + " ";
|
item->sort_text = SortTextForNumber(bitrate) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_Samplerate:
|
case GroupBy_Samplerate:{
|
||||||
samplerate = qMax(0, s.samplerate());
|
int samplerate = qMax(0, s.samplerate());
|
||||||
item->key = QString::number(samplerate);
|
item->key = QString::number(samplerate);
|
||||||
item->sort_text = SortTextForNumber(samplerate) + " ";
|
item->sort_text = SortTextForNumber(samplerate) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GroupBy_Bitdepth:
|
case GroupBy_Bitdepth:{
|
||||||
bitdepth = qMax(0, s.bitdepth());
|
int bitdepth = qMax(0, s.bitdepth());
|
||||||
item->key = QString::number(bitdepth);
|
item->key = QString::number(bitdepth);
|
||||||
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
item->sort_text = SortTextForNumber(bitdepth) + " ";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case GroupBy_Format:{
|
||||||
|
item->metadata.set_filetype(s.filetype());
|
||||||
|
item->metadata.set_samplerate(s.samplerate());
|
||||||
|
item->metadata.set_bitdepth(s.bitdepth());
|
||||||
|
if (s.samplerate() <= 0) {
|
||||||
|
item->key = s.TextForFiletype();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (s.bitdepth() <= 0) {
|
||||||
|
item->key = QString("%1 (%2)").arg(s.TextForFiletype()).arg(QString::number(s.samplerate() / 1000.0, 'G', 5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item->key = QString("%1 (%2/%3)").arg(s.TextForFiletype()).arg(QString::number(s.samplerate() / 1000.0, 'G', 5)).arg(QString::number(s.bitdepth()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GroupBy_None:
|
case GroupBy_None:
|
||||||
item->metadata = s;
|
item->metadata = s;
|
||||||
item->key = s.title();
|
item->key = s.title();
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
GroupBy_OriginalYearAlbum = 13,
|
GroupBy_OriginalYearAlbum = 13,
|
||||||
GroupBy_OriginalYear = 14,
|
GroupBy_OriginalYear = 14,
|
||||||
GroupBy_Samplerate = 15,
|
GroupBy_Samplerate = 15,
|
||||||
GroupBy_Bitdepth = 16
|
GroupBy_Bitdepth = 16,
|
||||||
|
GroupBy_Format = 17
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Grouping {
|
struct Grouping {
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ SongList CollectionView::GetSelectedSongs() const {
|
|||||||
void CollectionView::Organise() {
|
void CollectionView::Organise() {
|
||||||
|
|
||||||
if (!organise_dialog_)
|
if (!organise_dialog_)
|
||||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
organise_dialog_.reset(new OrganiseDialog(app_->task_manager(), app_->collection_backend()));
|
||||||
|
|
||||||
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
organise_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
|
||||||
organise_dialog_->SetCopy(false);
|
organise_dialog_->SetCopy(false);
|
||||||
@@ -664,18 +664,24 @@ void CollectionView::Organise() {
|
|||||||
else {
|
else {
|
||||||
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionView::EditTracks() {
|
void CollectionView::EditTracks() {
|
||||||
|
|
||||||
if (!edit_tag_dialog_) {
|
if (!edit_tag_dialog_) {
|
||||||
edit_tag_dialog_.reset(new EditTagDialog(app_, this));
|
edit_tag_dialog_.reset(new EditTagDialog(app_, this));
|
||||||
|
connect(edit_tag_dialog_.get(), SIGNAL(Error(QString)), SLOT(EditTagError(QString)));
|
||||||
}
|
}
|
||||||
edit_tag_dialog_->SetSongs(GetSelectedSongs());
|
edit_tag_dialog_->SetSongs(GetSelectedSongs());
|
||||||
edit_tag_dialog_->show();
|
edit_tag_dialog_->show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionView::EditTagError(const QString &message) {
|
||||||
|
emit Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionView::CopyToDevice() {
|
void CollectionView::CopyToDevice() {
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
if (!organise_dialog_)
|
if (!organise_dialog_)
|
||||||
|
|||||||
@@ -98,12 +98,15 @@ class CollectionView : public AutoExpandingTreeView {
|
|||||||
void SaveFocus();
|
void SaveFocus();
|
||||||
void RestoreFocus();
|
void RestoreFocus();
|
||||||
|
|
||||||
signals:
|
void EditTagError(const QString &message);
|
||||||
|
|
||||||
|
signals:
|
||||||
void ShowConfigDialog();
|
void ShowConfigDialog();
|
||||||
|
|
||||||
void TotalSongCountUpdated_();
|
void TotalSongCountUpdated_();
|
||||||
void TotalArtistCountUpdated_();
|
void TotalArtistCountUpdated_();
|
||||||
void TotalAlbumCountUpdated_();
|
void TotalAlbumCountUpdated_();
|
||||||
|
void Error(const QString &message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// QWidget
|
// QWidget
|
||||||
|
|||||||
@@ -684,6 +684,8 @@ QString CollectionWatcher::PickBestImage(const QStringList &images) {
|
|||||||
QString biggest_path;
|
QString biggest_path;
|
||||||
|
|
||||||
for (const QString &path : filtered) {
|
for (const QString &path : filtered) {
|
||||||
|
if (stop_requested_) return QString();
|
||||||
|
|
||||||
QImage image(path);
|
QImage image(path);
|
||||||
if (image.isNull()) continue;
|
if (image.isNull()) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,8 @@ class GroupByDialogPrivate {
|
|||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
Mapping,
|
Mapping,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
ordered_unique<tag<tag_index>,
|
ordered_unique<tag<tag_index>, member<Mapping, int, &Mapping::combo_box_index> >,
|
||||||
member<Mapping, int, &Mapping::combo_box_index> >,
|
ordered_unique<tag<tag_group_by>, member<Mapping, CollectionModel::GroupBy, &Mapping::group_by> > > > MappingContainer;
|
||||||
ordered_unique<tag<tag_group_by>,
|
|
||||||
member<Mapping, CollectionModel::GroupBy,
|
|
||||||
&Mapping::group_by> > > > MappingContainer;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MappingContainer mapping_;
|
MappingContainer mapping_;
|
||||||
@@ -85,33 +82,35 @@ GroupByDialog::GroupByDialog(QWidget *parent) : QDialog(parent), ui_(new Ui_Grou
|
|||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_None, 0));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_None, 0));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Album, 1));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Artist, 1));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Artist, 2));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_AlbumArtist, 2));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_AlbumArtist, 3));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Album, 3));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Composer, 4));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Disc, 4));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_FileType, 5));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Format, 5));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Genre, 6));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Genre, 6));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Year, 7));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_OriginalYear, 7));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_OriginalYear, 8));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Year, 8));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_YearAlbum, 9));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_OriginalYearAlbum, 9));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_OriginalYearAlbum, 10));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_YearAlbum, 10));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitrate, 11));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Composer, 11));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Samplerate, 12));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Performer, 12));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitdepth, 13));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Grouping, 13));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Disc, 14));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_FileType, 14));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Performer, 15));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Samplerate, 15));
|
||||||
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Grouping, 16));
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitdepth, 16));
|
||||||
|
p_->mapping_.insert(Mapping(CollectionModel::GroupBy_Bitrate, 17));
|
||||||
|
|
||||||
connect(ui_->buttonbox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(Reset()));
|
connect(ui_->buttonbox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(Reset()));
|
||||||
|
|
||||||
resize(sizeHint());
|
resize(sizeHint());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupByDialog::~GroupByDialog() {}
|
GroupByDialog::~GroupByDialog() {}
|
||||||
|
|
||||||
void GroupByDialog::Reset() {
|
void GroupByDialog::Reset() {
|
||||||
ui_->combobox_first->setCurrentIndex(2); // Artist
|
ui_->combobox_first->setCurrentIndex(2); // Album Artist
|
||||||
ui_->combobox_second->setCurrentIndex(1); // Album
|
ui_->combobox_second->setCurrentIndex(3); // Album
|
||||||
ui_->combobox_third->setCurrentIndex(0); // None
|
ui_->combobox_third->setCurrentIndex(0); // None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<iconset resource="../../data/icons.qrc">
|
<iconset resource="../../data/icons.qrc">
|
||||||
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
|
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="layout_groupbydialog">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -48,11 +48,6 @@
|
|||||||
<string>None</string>
|
<string>None</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Album</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Artist</string>
|
<string>Artist</string>
|
||||||
@@ -65,12 +60,17 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Composer</string>
|
<string>Album</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>File type</string>
|
<string>Disc</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Format</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -78,11 +78,6 @@
|
|||||||
<string>Genre</string>
|
<string>Genre</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Year</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Original year</string>
|
<string>Original year</string>
|
||||||
@@ -90,7 +85,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Year - Album</string>
|
<string>Year</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -100,7 +95,27 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Bitrate</string>
|
<string>Year - Album</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Composer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Performer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Grouping</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>File type</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -115,17 +130,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Disc</string>
|
<string>Bitrate</string>
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Performer</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Grouping</string>
|
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -144,11 +149,6 @@
|
|||||||
<string>None</string>
|
<string>None</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Album</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Artist</string>
|
<string>Artist</string>
|
||||||
@@ -161,12 +161,17 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Composer</string>
|
<string>Album</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>File type</string>
|
<string>Disc</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Format</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -174,11 +179,6 @@
|
|||||||
<string>Genre</string>
|
<string>Genre</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Year</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Original year</string>
|
<string>Original year</string>
|
||||||
@@ -186,7 +186,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Year - Album</string>
|
<string>Year</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -196,7 +196,27 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Bitrate</string>
|
<string>Year - Album</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Composer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Performer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Grouping</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>File type</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -211,17 +231,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Disc</string>
|
<string>Bitrate</string>
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Performer</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Grouping</string>
|
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -240,11 +250,6 @@
|
|||||||
<string>None</string>
|
<string>None</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Album</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Artist</string>
|
<string>Artist</string>
|
||||||
@@ -257,12 +262,17 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Composer</string>
|
<string>Album</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>File type</string>
|
<string>Disc</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Format</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -270,11 +280,6 @@
|
|||||||
<string>Genre</string>
|
<string>Genre</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Year</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Original year</string>
|
<string>Original year</string>
|
||||||
@@ -282,7 +287,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Year - Album</string>
|
<string>Year</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -292,7 +297,27 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Bitrate</string>
|
<string>Year - Album</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Composer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Performer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Grouping</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>File type</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -307,17 +332,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Disc</string>
|
<string>Bitrate</string>
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Performer</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Grouping</string>
|
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -326,7 +341,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="spacer_bottom">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g)
|
|||||||
case CollectionModel::GroupBy_None: {
|
case CollectionModel::GroupBy_None: {
|
||||||
return tr("None");
|
return tr("None");
|
||||||
}
|
}
|
||||||
|
case CollectionModel::GroupBy_AlbumArtist: {
|
||||||
|
return tr("Album artist");
|
||||||
|
}
|
||||||
case CollectionModel::GroupBy_Artist: {
|
case CollectionModel::GroupBy_Artist: {
|
||||||
return tr("Artist");
|
return tr("Artist");
|
||||||
}
|
}
|
||||||
@@ -95,9 +98,6 @@ QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g)
|
|||||||
case CollectionModel::GroupBy_Genre: {
|
case CollectionModel::GroupBy_Genre: {
|
||||||
return tr("Genre");
|
return tr("Genre");
|
||||||
}
|
}
|
||||||
case CollectionModel::GroupBy_AlbumArtist: {
|
|
||||||
return tr("Album artist");
|
|
||||||
}
|
|
||||||
case CollectionModel::GroupBy_FileType: {
|
case CollectionModel::GroupBy_FileType: {
|
||||||
return tr("File type");
|
return tr("File type");
|
||||||
}
|
}
|
||||||
@@ -107,15 +107,15 @@ QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g)
|
|||||||
case CollectionModel::GroupBy_Grouping: {
|
case CollectionModel::GroupBy_Grouping: {
|
||||||
return tr("Grouping");
|
return tr("Grouping");
|
||||||
}
|
}
|
||||||
case CollectionModel::GroupBy_Bitrate: {
|
|
||||||
return tr("Bitrate");
|
|
||||||
}
|
|
||||||
case CollectionModel::GroupBy_Samplerate: {
|
case CollectionModel::GroupBy_Samplerate: {
|
||||||
return tr("Sample rate");
|
return tr("Sample rate");
|
||||||
}
|
}
|
||||||
case CollectionModel::GroupBy_Bitdepth: {
|
case CollectionModel::GroupBy_Bitdepth: {
|
||||||
return tr("Bit depth");
|
return tr("Bit depth");
|
||||||
}
|
}
|
||||||
|
case CollectionModel::GroupBy_Bitrate: {
|
||||||
|
return tr("Bitrate");
|
||||||
|
}
|
||||||
case CollectionModel::GroupBy_Disc: {
|
case CollectionModel::GroupBy_Disc: {
|
||||||
return tr("Disc");
|
return tr("Disc");
|
||||||
}
|
}
|
||||||
@@ -125,6 +125,9 @@ QString SavedGroupingManager::GroupByToString(const CollectionModel::GroupBy &g)
|
|||||||
case CollectionModel::GroupBy_OriginalYear: {
|
case CollectionModel::GroupBy_OriginalYear: {
|
||||||
return tr("Original year");
|
return tr("Original year");
|
||||||
}
|
}
|
||||||
|
case CollectionModel::GroupBy_Format: {
|
||||||
|
return tr("Format");
|
||||||
|
}
|
||||||
default: { return tr("Unknown"); }
|
default: { return tr("Unknown"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
#cmakedefine HAVE_SPARKLE
|
#cmakedefine HAVE_SPARKLE
|
||||||
#cmakedefine HAVE_CHROMAPRINT
|
#cmakedefine HAVE_CHROMAPRINT
|
||||||
#cmakedefine HAVE_TAGLIB_DSFFILE
|
#cmakedefine HAVE_TAGLIB_DSFFILE
|
||||||
#cmakedefine HAVE_DZMEDIA
|
|
||||||
#cmakedefine HAVE_GLOBALSHORTCUTS
|
#cmakedefine HAVE_GLOBALSHORTCUTS
|
||||||
#cmakedefine IMOBILEDEVICE_USES_UDIDS
|
#cmakedefine IMOBILEDEVICE_USES_UDIDS
|
||||||
#cmakedefine USE_INSTALL_PREFIX
|
#cmakedefine USE_INSTALL_PREFIX
|
||||||
@@ -48,10 +47,8 @@
|
|||||||
#cmakedefine HAVE_VLC
|
#cmakedefine HAVE_VLC
|
||||||
#cmakedefine HAVE_XINE
|
#cmakedefine HAVE_XINE
|
||||||
#cmakedefine HAVE_PHONON
|
#cmakedefine HAVE_PHONON
|
||||||
#cmakedefine HAVE_DEEZER
|
|
||||||
|
|
||||||
#cmakedefine HAVE_STREAM_TIDAL
|
#cmakedefine HAVE_STREAM_TIDAL
|
||||||
#cmakedefine HAVE_STREAM_DEEZER
|
|
||||||
|
|
||||||
#cmakedefine HAVE_KEYSYMDEF_H
|
#cmakedefine HAVE_KEYSYMDEF_H
|
||||||
#cmakedefine HAVE_XF86KEYSYM_H
|
#cmakedefine HAVE_XF86KEYSYM_H
|
||||||
@@ -60,5 +57,6 @@
|
|||||||
|
|
||||||
#define USE_BUNDLE_DIR "${USE_BUNDLE_DIR}"
|
#define USE_BUNDLE_DIR "${USE_BUNDLE_DIR}"
|
||||||
|
|
||||||
#endif // CONFIG_H_IN
|
#cmakedefine HAVE_TRANSLATIONS
|
||||||
|
|
||||||
|
#endif // CONFIG_H_IN
|
||||||
|
|||||||
@@ -232,9 +232,9 @@ void ContextView::NoSong() {
|
|||||||
"font-weight: Regular;"
|
"font-weight: Regular;"
|
||||||
);
|
);
|
||||||
|
|
||||||
ui_->label_stop_top->setText("No song playing");
|
ui_->label_stop_top->setText(tr("No song playing"));
|
||||||
|
|
||||||
QString html = QString(
|
QString html = tr(
|
||||||
"%1 songs<br />\n"
|
"%1 songs<br />\n"
|
||||||
"%2 artists<br />\n"
|
"%2 artists<br />\n"
|
||||||
"%3 albums<br />\n"
|
"%3 albums<br />\n"
|
||||||
@@ -404,7 +404,7 @@ void ContextView::SetSong(const Song &song) {
|
|||||||
if (albumlist.count() > 1) {
|
if (albumlist.count() > 1) {
|
||||||
ui_->label_play_albums->setVisible(true);
|
ui_->label_play_albums->setVisible(true);
|
||||||
ui_->label_play_albums->setMinimumSize(0, 20);
|
ui_->label_play_albums->setMinimumSize(0, 20);
|
||||||
ui_->label_play_albums->setText(QString("<b>Albums by %1</b>").arg( song.artist().toHtmlEscaped()));
|
ui_->label_play_albums->setText(tr("<b>Albums by %1</b>").arg( song.artist().toHtmlEscaped()));
|
||||||
ui_->label_play_albums->setStyleSheet("background-color: #3DADE8; color: rgb(255, 255, 255); font: 11pt;");
|
ui_->label_play_albums->setStyleSheet("background-color: #3DADE8; color: rgb(255, 255, 255); font: 11pt;");
|
||||||
for (CollectionBackend::Album album : albumlist) {
|
for (CollectionBackend::Album album : albumlist) {
|
||||||
SongList songs = app_->collection_backend()->GetSongs(song.artist(), album.album_name, opt);
|
SongList songs = app_->collection_backend()->GetSongs(song.artist(), album.album_name, opt);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>927</height>
|
<height>900</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="layout_container">
|
<layout class="QVBoxLayout" name="layout_container">
|
||||||
@@ -57,8 +57,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>396</width>
|
<width>394</width>
|
||||||
<height>923</height>
|
<height>894</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
@@ -175,8 +175,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>396</width>
|
<width>394</width>
|
||||||
<height>923</height>
|
<height>894</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
@@ -526,6 +526,12 @@
|
|||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -32,19 +32,17 @@
|
|||||||
#include "appearance.h"
|
#include "appearance.h"
|
||||||
#include "settings/appearancesettingspage.h"
|
#include "settings/appearancesettingspage.h"
|
||||||
|
|
||||||
const char *Appearance::kUseCustomColorSet = "use-custom-set";
|
|
||||||
const char *Appearance::kForegroundColor = "foreground-color";
|
|
||||||
const char *Appearance::kBackgroundColor = "background-color";
|
|
||||||
|
|
||||||
const QPalette Appearance::kDefaultPalette = QPalette();
|
const QPalette Appearance::kDefaultPalette = QPalette();
|
||||||
|
|
||||||
Appearance::Appearance(QObject *parent) : QObject(parent) {
|
Appearance::Appearance(QObject *parent) : QObject(parent) {
|
||||||
|
|
||||||
|
QPalette p = QApplication::palette();
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
||||||
QPalette p = QApplication::palette();
|
background_color_ = s.value(AppearanceSettingsPage::kBackgroundColor, p.color(QPalette::WindowText)).value<QColor>();
|
||||||
background_color_ = s.value(kBackgroundColor, p.color(QPalette::WindowText)).value<QColor>();
|
foreground_color_ = s.value(AppearanceSettingsPage::kForegroundColor, p.color(QPalette::Window)).value<QColor>();
|
||||||
foreground_color_ = s.value(kForegroundColor, p.color(QPalette::Window)).value<QColor>();
|
s.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +50,9 @@ void Appearance::LoadUserTheme() {
|
|||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
||||||
bool use_a_custom_color_set = s.value(kUseCustomColorSet).toBool();
|
bool use_a_custom_color_set = s.value(AppearanceSettingsPage::kUseCustomColorSet).toBool();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
if (!use_a_custom_color_set) return;
|
if (!use_a_custom_color_set) return;
|
||||||
|
|
||||||
ChangeForegroundColor(foreground_color_);
|
ChangeForegroundColor(foreground_color_);
|
||||||
|
|||||||
@@ -30,18 +30,14 @@
|
|||||||
class Appearance : public QObject {
|
class Appearance : public QObject {
|
||||||
public:
|
public:
|
||||||
explicit Appearance(QObject *parent = nullptr);
|
explicit Appearance(QObject *parent = nullptr);
|
||||||
// Load the user preferred theme, which could the default system theme or a custom set of colors that user has chosen
|
|
||||||
|
static const QPalette kDefaultPalette;
|
||||||
|
|
||||||
void LoadUserTheme();
|
void LoadUserTheme();
|
||||||
void ResetToSystemDefaultTheme();
|
void ResetToSystemDefaultTheme();
|
||||||
void ChangeForegroundColor(const QColor &color);
|
void ChangeForegroundColor(const QColor &color);
|
||||||
void ChangeBackgroundColor(const QColor &color);
|
void ChangeBackgroundColor(const QColor &color);
|
||||||
|
|
||||||
static const char *kSettingsGroup;
|
|
||||||
static const char *kUseCustomColorSet;
|
|
||||||
static const char *kForegroundColor;
|
|
||||||
static const char *kBackgroundColor;
|
|
||||||
static const QPalette kDefaultPalette;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QColor foreground_color_;
|
QColor foreground_color_;
|
||||||
QColor background_color_;
|
QColor background_color_;
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
#include "lyrics/lyricsproviders.h"
|
#include "lyrics/lyricsproviders.h"
|
||||||
#include "lyrics/lyricsprovider.h"
|
#include "lyrics/lyricsprovider.h"
|
||||||
#include "lyrics/auddlyricsprovider.h"
|
#include "lyrics/auddlyricsprovider.h"
|
||||||
#include "lyrics/apiseedslyricsprovider.h"
|
|
||||||
|
|
||||||
#include "internet/internetservices.h"
|
#include "internet/internetservices.h"
|
||||||
#include "internet/internetsearch.h"
|
#include "internet/internetsearch.h"
|
||||||
@@ -66,9 +65,6 @@
|
|||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
# include "tidal/tidalservice.h"
|
# include "tidal/tidalservice.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
# include "deezer/deezerservice.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "scrobbler/audioscrobbler.h"
|
#include "scrobbler/audioscrobbler.h"
|
||||||
|
|
||||||
@@ -120,24 +116,17 @@ class ApplicationImpl {
|
|||||||
lyrics_providers_([=]() {
|
lyrics_providers_([=]() {
|
||||||
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
LyricsProviders *lyrics_providers = new LyricsProviders(app);
|
||||||
lyrics_providers->AddProvider(new AuddLyricsProvider(app));
|
lyrics_providers->AddProvider(new AuddLyricsProvider(app));
|
||||||
lyrics_providers->AddProvider(new APISeedsLyricsProvider(app));
|
|
||||||
return lyrics_providers;
|
return lyrics_providers;
|
||||||
}),
|
}),
|
||||||
internet_services_([=]() {
|
internet_services_([=]() {
|
||||||
InternetServices *internet_services = new InternetServices(app);
|
InternetServices *internet_services = new InternetServices(app);
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
internet_services->AddService(new TidalService(app, internet_services));
|
internet_services->AddService(new TidalService(app, internet_services));
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
internet_services->AddService(new DeezerService(app, internet_services));
|
|
||||||
#endif
|
#endif
|
||||||
return internet_services;
|
return internet_services;
|
||||||
}),
|
}),
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
tidal_search_([=]() { return new InternetSearch(app, Song::Source_Tidal, app); }),
|
tidal_search_([=]() { return new InternetSearch(app, Song::Source_Tidal, app); }),
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
deezer_search_([=]() { return new InternetSearch(app, Song::Source_Deezer, app); }),
|
|
||||||
#endif
|
#endif
|
||||||
scrobbler_([=]() { return new AudioScrobbler(app, app); })
|
scrobbler_([=]() { return new AudioScrobbler(app, app); })
|
||||||
{}
|
{}
|
||||||
@@ -161,9 +150,6 @@ class ApplicationImpl {
|
|||||||
Lazy<InternetServices> internet_services_;
|
Lazy<InternetServices> internet_services_;
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
Lazy<InternetSearch> tidal_search_;
|
Lazy<InternetSearch> tidal_search_;
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
Lazy<InternetSearch> deezer_search_;
|
|
||||||
#endif
|
#endif
|
||||||
Lazy<AudioScrobbler> scrobbler_;
|
Lazy<AudioScrobbler> scrobbler_;
|
||||||
|
|
||||||
@@ -236,7 +222,4 @@ InternetServices *Application::internet_services() const { return p_->internet_s
|
|||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
InternetSearch *Application::tidal_search() const { return p_->tidal_search_.get(); }
|
InternetSearch *Application::tidal_search() const { return p_->tidal_search_.get(); }
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
InternetSearch *Application::deezer_search() const { return p_->deezer_search_.get(); }
|
|
||||||
#endif
|
|
||||||
AudioScrobbler *Application::scrobbler() const { return p_->scrobbler_.get(); }
|
AudioScrobbler *Application::scrobbler() const { return p_->scrobbler_.get(); }
|
||||||
|
|||||||
@@ -96,9 +96,6 @@ class Application : public QObject {
|
|||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
InternetSearch *tidal_search() const;
|
InternetSearch *tidal_search() const;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
InternetSearch *deezer_search() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AudioScrobbler *scrobbler() const;
|
AudioScrobbler *scrobbler() const;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
|
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2013, 2017-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,28 +21,64 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QtDebug>
|
#include <QStandardPaths>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
#include "settings/appearancesettingspage.h"
|
||||||
#include "iconloader.h"
|
#include "iconloader.h"
|
||||||
|
|
||||||
|
bool IconLoader::system_icons_ = false;
|
||||||
|
bool IconLoader::custom_icons_ = false;
|
||||||
|
|
||||||
|
void IconLoader::Init() {
|
||||||
|
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
|
||||||
|
system_icons_ = s.value("system_icons", false).toBool();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
QDir dir;
|
||||||
|
if (dir.exists(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/icons")) {
|
||||||
|
custom_icons_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
QIcon IconLoader::Load(const QString &name, const int size) {
|
QIcon IconLoader::Load(const QString &name, const int size) {
|
||||||
|
|
||||||
QIcon ret;
|
QIcon ret;
|
||||||
|
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
qLog(Error) << "Icon name is empty!";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
QList<int> sizes;
|
QList<int> sizes;
|
||||||
sizes.clear();
|
sizes.clear();
|
||||||
if (size == 0) { sizes << 22 << 32 << 48 << 64; }
|
if (size == 0) { sizes << 22 << 32 << 48 << 64; }
|
||||||
else sizes << size;
|
else sizes << size;
|
||||||
|
|
||||||
if (name.isEmpty()) {
|
if (system_icons_) {
|
||||||
qLog(Error) << "Icon name is empty!";
|
ret = QIcon::fromTheme(name);
|
||||||
return ret;
|
if (!ret.isNull()) return ret;
|
||||||
|
qLog(Warning) << "Couldn't load icon" << name << "from system theme icons.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (custom_icons_) {
|
||||||
|
QString custom_icon_path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/icons/%1x%2/%3.png";
|
||||||
|
for (int s : sizes) {
|
||||||
|
QString filename(custom_icon_path.arg(s).arg(s).arg(name));
|
||||||
|
if (QFile::exists(filename)) ret.addFile(filename, QSize(s, s));
|
||||||
|
}
|
||||||
|
if (!ret.isNull()) return ret;
|
||||||
|
qLog(Warning) << "Couldn't load icon" << name << "from custom icons.";
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString path(":/icons/%1x%2/%3.png");
|
const QString path(":/icons/%1x%2/%3.png");
|
||||||
@@ -51,13 +87,6 @@ QIcon IconLoader::Load(const QString &name, const int size) {
|
|||||||
if (QFile::exists(filename)) ret.addFile(filename, QSize(s, s));
|
if (QFile::exists(filename)) ret.addFile(filename, QSize(s, s));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load icon from system theme only if it hasn't been found
|
|
||||||
if (ret.isNull()) {
|
|
||||||
ret = QIcon::fromTheme(name);
|
|
||||||
if (!ret.isNull()) return ret;
|
|
||||||
qLog(Warning) << "Couldn't load icon" << name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Strawberry Music Player
|
* Strawberry Music Player
|
||||||
* This file was part of Clementine.
|
* This file was part of Clementine.
|
||||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||||
|
* Copyright 2013, 2017-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
*
|
*
|
||||||
* Strawberry is free software: you can redistribute it and/or modify
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,10 +28,12 @@
|
|||||||
|
|
||||||
class IconLoader {
|
class IconLoader {
|
||||||
public:
|
public:
|
||||||
|
static void Init();
|
||||||
static QIcon Load(const QString &name, const int size = 0);
|
static QIcon Load(const QString &name, const int size = 0);
|
||||||
private:
|
private:
|
||||||
IconLoader() {}
|
IconLoader() {}
|
||||||
|
static bool system_icons_;
|
||||||
|
static bool custom_icons_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ICONLOADER_H
|
#endif // ICONLOADER_H
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
#include "organise/organisedialog.h"
|
#include "organise/organisedialog.h"
|
||||||
#include "widgets/fancytabwidget.h"
|
#include "widgets/fancytabwidget.h"
|
||||||
#include "widgets/playingwidget.h"
|
#include "widgets/playingwidget.h"
|
||||||
#include "widgets/sliderwidget.h"
|
#include "widgets/volumeslider.h"
|
||||||
#include "widgets/fileview.h"
|
#include "widgets/fileview.h"
|
||||||
#include "widgets/multiloadingindicator.h"
|
#include "widgets/multiloadingindicator.h"
|
||||||
#include "widgets/osd.h"
|
#include "widgets/osd.h"
|
||||||
@@ -131,13 +131,11 @@
|
|||||||
#include "transcoder/transcodedialog.h"
|
#include "transcoder/transcodedialog.h"
|
||||||
#include "settings/settingsdialog.h"
|
#include "settings/settingsdialog.h"
|
||||||
#include "settings/behavioursettingspage.h"
|
#include "settings/behavioursettingspage.h"
|
||||||
|
#include "settings/backendsettingspage.h"
|
||||||
#include "settings/playlistsettingspage.h"
|
#include "settings/playlistsettingspage.h"
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
# include "settings/tidalsettingspage.h"
|
# include "settings/tidalsettingspage.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
# include "settings/deezersettingspage.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "internet/internetservices.h"
|
#include "internet/internetservices.h"
|
||||||
#include "internet/internetservice.h"
|
#include "internet/internetservice.h"
|
||||||
@@ -199,15 +197,12 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
//organise_dialog_(new OrganiseDialog(app_->task_manager())),
|
//organise_dialog_(new OrganiseDialog(app_->task_manager())),
|
||||||
equalizer_(new Equalizer),
|
equalizer_(new Equalizer),
|
||||||
organise_dialog_([=]() {
|
organise_dialog_([=]() {
|
||||||
OrganiseDialog *dialog = new OrganiseDialog(app->task_manager());
|
OrganiseDialog *dialog = new OrganiseDialog(app->task_manager(), app->collection_backend());
|
||||||
dialog->SetDestinationModel(app->collection()->model()->directory_model());
|
dialog->SetDestinationModel(app->collection()->model()->directory_model());
|
||||||
return dialog;
|
return dialog;
|
||||||
}),
|
}),
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
tidal_search_view_(new InternetSearchView(app_, app_->tidal_search(), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)),
|
tidal_search_view_(new InternetSearchView(app_, app_->tidal_search(), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)),
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
deezer_search_view_(new InternetSearchView(app_, app_->deezer_search(), DeezerSettingsPage::kSettingsGroup, SettingsDialog::Page_Deezer, this)),
|
|
||||||
#endif
|
#endif
|
||||||
playlist_menu_(new QMenu(this)),
|
playlist_menu_(new QMenu(this)),
|
||||||
playlist_add_to_another_(nullptr),
|
playlist_add_to_another_(nullptr),
|
||||||
@@ -219,9 +214,11 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
was_maximized_(true),
|
was_maximized_(true),
|
||||||
saved_playback_position_(0),
|
saved_playback_position_(0),
|
||||||
saved_playback_state_(Engine::Empty),
|
saved_playback_state_(Engine::Empty),
|
||||||
doubleclick_addmode_(AddBehaviour_Append),
|
playing_widget_(true),
|
||||||
doubleclick_playmode_(PlayBehaviour_Never),
|
doubleclick_addmode_(BehaviourSettingsPage::AddBehaviour_Append),
|
||||||
menu_playmode_(PlayBehaviour_Never) {
|
doubleclick_playmode_(BehaviourSettingsPage::PlayBehaviour_Never),
|
||||||
|
menu_playmode_(BehaviourSettingsPage::PlayBehaviour_Never)
|
||||||
|
{
|
||||||
|
|
||||||
qLog(Debug) << "Starting";
|
qLog(Debug) << "Starting";
|
||||||
|
|
||||||
@@ -248,27 +245,20 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
context_view_->SetApplication(app_, collection_view_->view(), album_cover_choice_controller_);
|
context_view_->SetApplication(app_, collection_view_->view(), album_cover_choice_controller_);
|
||||||
ui_->widget_playing->SetApplication(app_, album_cover_choice_controller_);
|
ui_->widget_playing->SetApplication(app_, album_cover_choice_controller_);
|
||||||
|
|
||||||
int volume = app_->player()->GetVolume();
|
|
||||||
ui_->volume->setValue(volume);
|
|
||||||
VolumeChanged(volume);
|
|
||||||
|
|
||||||
// Initialise the search widget
|
// Initialise the search widget
|
||||||
StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker());
|
StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker());
|
||||||
|
|
||||||
// Add tabs to the fancy tab widget
|
// Add tabs to the fancy tab widget
|
||||||
ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), "Context");
|
ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), tr("Context"));
|
||||||
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), "Collection");
|
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
|
||||||
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), "Files");
|
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
|
||||||
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), "Playlists");
|
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||||
ui_->tabs->addTab(queue_view_, IconLoader::Load("footsteps"), "Queue");
|
ui_->tabs->addTab(queue_view_, IconLoader::Load("footsteps"), tr("Queue"));
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), "Devices");
|
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices"));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal");
|
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal"));
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Add the playing widget to the fancy tab widget
|
// Add the playing widget to the fancy tab widget
|
||||||
@@ -286,6 +276,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
app_->player()->SetAnalyzer(ui_->analyzer);
|
app_->player()->SetAnalyzer(ui_->analyzer);
|
||||||
app_->player()->SetEqualizer(equalizer_.get());
|
app_->player()->SetEqualizer(equalizer_.get());
|
||||||
app_->player()->Init();
|
app_->player()->Init();
|
||||||
|
int volume = app_->player()->GetVolume();
|
||||||
|
ui_->volume->setValue(volume);
|
||||||
|
VolumeChanged(volume);
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
qLog(Debug) << "Creating models";
|
qLog(Debug) << "Creating models";
|
||||||
@@ -499,6 +492,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
// Collection connections
|
// Collection connections
|
||||||
connect(collection_view_->view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
connect(collection_view_->view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
||||||
connect(collection_view_->view(), SIGNAL(ShowConfigDialog()), SLOT(ShowCollectionConfig()));
|
connect(collection_view_->view(), SIGNAL(ShowConfigDialog()), SLOT(ShowCollectionConfig()));
|
||||||
|
connect(collection_view_->view(), SIGNAL(Error(QString)), SLOT(ShowErrorDialog(QString)));
|
||||||
connect(app_->collection_model(), SIGNAL(TotalSongCountUpdated(int)), collection_view_->view(), SLOT(TotalSongCountUpdated(int)));
|
connect(app_->collection_model(), SIGNAL(TotalSongCountUpdated(int)), collection_view_->view(), SLOT(TotalSongCountUpdated(int)));
|
||||||
connect(app_->collection_model(), SIGNAL(TotalArtistCountUpdated(int)), collection_view_->view(), SLOT(TotalArtistCountUpdated(int)));
|
connect(app_->collection_model(), SIGNAL(TotalArtistCountUpdated(int)), collection_view_->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||||
connect(app_->collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), collection_view_->view(), SLOT(TotalAlbumCountUpdated(int)));
|
connect(app_->collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), collection_view_->view(), SLOT(TotalAlbumCountUpdated(int)));
|
||||||
@@ -544,9 +538,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
connect(tidal_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
connect(tidal_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
connect(deezer_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Playlist menu
|
// Playlist menu
|
||||||
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, SLOT(PlaylistPlay()));
|
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, SLOT(PlaylistPlay()));
|
||||||
@@ -819,36 +810,43 @@ void MainWindow::ReloadSettings() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
|
||||||
doubleclick_addmode_ = AddBehaviour(settings.value("doubleclick_addmode", AddBehaviour_Append).toInt());
|
playing_widget_ = settings.value("playing_widget", true).toBool();
|
||||||
doubleclick_playmode_ = PlayBehaviour(settings.value("doubleclick_playmode", PlayBehaviour_IfStopped).toInt());
|
if (playing_widget_ != ui_->widget_playing->IsEnabled()) TabSwitched();
|
||||||
doubleclick_playlist_addmode_ = PlaylistAddBehaviour(settings.value("doubleclick_playlist_addmode", PlaylistAddBehaviour_Play).toInt());
|
doubleclick_addmode_ = BehaviourSettingsPage::AddBehaviour(settings.value("doubleclick_addmode", BehaviourSettingsPage::AddBehaviour_Append).toInt());
|
||||||
menu_playmode_ = PlayBehaviour(settings.value("menu_playmode", PlayBehaviour_IfStopped).toInt());
|
doubleclick_playmode_ = BehaviourSettingsPage::PlayBehaviour(settings.value("doubleclick_playmode", BehaviourSettingsPage::PlayBehaviour_IfStopped).toInt());
|
||||||
|
doubleclick_playlist_addmode_ = BehaviourSettingsPage::PlaylistAddBehaviour(settings.value("doubleclick_playlist_addmode", BehaviourSettingsPage::PlaylistAddBehaviour_Play).toInt());
|
||||||
|
menu_playmode_ = BehaviourSettingsPage::PlayBehaviour(settings.value("menu_playmode", BehaviourSettingsPage::PlayBehaviour_IfStopped).toInt());
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
settings.beginGroup(kSettingsGroup);
|
settings.beginGroup(kSettingsGroup);
|
||||||
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings.value("search_for_cover_auto", true).toBool());
|
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings.value("search_for_cover_auto", true).toBool());
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
settings.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
|
bool volume_control = settings.value("volume_control", true).toBool();
|
||||||
|
settings.endGroup();
|
||||||
|
if (volume_control != ui_->volume->isEnabled()) {
|
||||||
|
ui_->volume->SetEnabled(volume_control);
|
||||||
|
if (volume_control) {
|
||||||
|
if (!ui_->action_mute->isVisible()) ui_->action_mute->setVisible(true);
|
||||||
|
if (tray_icon_ && !tray_icon_->MuteEnabled()) tray_icon_->SetMuteEnabled(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ui_->action_mute->isVisible()) ui_->action_mute->setVisible(false);
|
||||||
|
if (tray_icon_ && tray_icon_->MuteEnabled()) tray_icon_->SetMuteEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
settings.beginGroup(TidalSettingsPage::kSettingsGroup);
|
settings.beginGroup(TidalSettingsPage::kSettingsGroup);
|
||||||
bool enable_tidal = settings.value("enabled", false).toBool();
|
bool enable_tidal = settings.value("enabled", false).toBool();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
if (enable_tidal)
|
if (enable_tidal)
|
||||||
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal");
|
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal"));
|
||||||
else
|
else
|
||||||
ui_->tabs->delTab("Tidal");
|
ui_->tabs->delTab("Tidal");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
settings.beginGroup(DeezerSettingsPage::kSettingsGroup);
|
|
||||||
bool enable_deezer = settings.value("enabled", false).toBool();
|
|
||||||
settings.endGroup();
|
|
||||||
if (enable_deezer)
|
|
||||||
ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer");
|
|
||||||
else
|
|
||||||
ui_->tabs->delTab("Deezer");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ReloadAllSettings() {
|
void MainWindow::ReloadAllSettings() {
|
||||||
@@ -862,12 +860,11 @@ void MainWindow::ReloadAllSettings() {
|
|||||||
osd_->ReloadSettings();
|
osd_->ReloadSettings();
|
||||||
collection_view_->ReloadSettings();
|
collection_view_->ReloadSettings();
|
||||||
ui_->playlist->view()->ReloadSettings();
|
ui_->playlist->view()->ReloadSettings();
|
||||||
|
album_cover_choice_controller_->ReloadSettings();
|
||||||
|
if (cover_manager_.get()) cover_manager_->ReloadSettings();
|
||||||
#ifdef HAVE_STREAM_TIDAL
|
#ifdef HAVE_STREAM_TIDAL
|
||||||
tidal_search_view_->ReloadSettings();
|
tidal_search_view_->ReloadSettings();
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STREAM_DEEZER
|
|
||||||
deezer_search_view_->ReloadSettings();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -997,10 +994,12 @@ void MainWindow::resizeEvent(QResizeEvent *event) {
|
|||||||
|
|
||||||
void MainWindow::TabSwitched() {
|
void MainWindow::TabSwitched() {
|
||||||
|
|
||||||
if (ui_->tabs->tabBar()->tabData(ui_->tabs->currentIndex()).toString().toLower() == "context")
|
if (playing_widget_ && ui_->tabs->tabBar()->tabData(ui_->tabs->currentIndex()).toString().toLower() != "context") {
|
||||||
ui_->widget_playing->SetDisabled();
|
|
||||||
else
|
|
||||||
ui_->widget_playing->SetEnabled();
|
ui_->widget_playing->SetEnabled();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ui_->widget_playing->SetDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
if (!initialised_) return;
|
if (!initialised_) return;
|
||||||
|
|
||||||
@@ -1109,12 +1108,12 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
|||||||
QModelIndexList dummyIndexList;
|
QModelIndexList dummyIndexList;
|
||||||
|
|
||||||
switch (doubleclick_playlist_addmode_) {
|
switch (doubleclick_playlist_addmode_) {
|
||||||
case PlaylistAddBehaviour_Play:
|
case BehaviourSettingsPage::PlaylistAddBehaviour_Play:
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
app_->player()->PlayAt(row, Engine::Manual, true);
|
app_->player()->PlayAt(row, Engine::Manual, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PlaylistAddBehaviour_Enqueue:
|
case BehaviourSettingsPage::PlaylistAddBehaviour_Enqueue:
|
||||||
dummyIndexList.append(index);
|
dummyIndexList.append(index);
|
||||||
app_->playlist_manager()->current()->queue()->ToggleTracks(dummyIndexList);
|
app_->playlist_manager()->current()->queue()->ToggleTracks(dummyIndexList);
|
||||||
if (app_->player()->GetState() != Engine::Playing) {
|
if (app_->player()->GetState() != Engine::Playing) {
|
||||||
@@ -1242,42 +1241,42 @@ void MainWindow::UpdateTrackSliderPosition() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ApplyAddBehaviour(MainWindow::AddBehaviour b, MimeData *data) const {
|
void MainWindow::ApplyAddBehaviour(BehaviourSettingsPage::AddBehaviour b, MimeData *data) const {
|
||||||
|
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case AddBehaviour_Append:
|
case BehaviourSettingsPage::AddBehaviour_Append:
|
||||||
data->clear_first_ = false;
|
data->clear_first_ = false;
|
||||||
data->enqueue_now_ = false;
|
data->enqueue_now_ = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddBehaviour_Enqueue:
|
case BehaviourSettingsPage::AddBehaviour_Enqueue:
|
||||||
data->clear_first_ = false;
|
data->clear_first_ = false;
|
||||||
data->enqueue_now_ = true;
|
data->enqueue_now_ = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddBehaviour_Load:
|
case BehaviourSettingsPage::AddBehaviour_Load:
|
||||||
data->clear_first_ = true;
|
data->clear_first_ = true;
|
||||||
data->enqueue_now_ = false;
|
data->enqueue_now_ = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddBehaviour_OpenInNew:
|
case BehaviourSettingsPage::AddBehaviour_OpenInNew:
|
||||||
data->open_in_new_playlist_ = true;
|
data->open_in_new_playlist_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ApplyPlayBehaviour(MainWindow::PlayBehaviour b, MimeData *data) const {
|
void MainWindow::ApplyPlayBehaviour(BehaviourSettingsPage::PlayBehaviour b, MimeData *data) const {
|
||||||
|
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case PlayBehaviour_Always:
|
case BehaviourSettingsPage::PlayBehaviour_Always:
|
||||||
data->play_now_ = true;
|
data->play_now_ = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PlayBehaviour_Never:
|
case BehaviourSettingsPage::PlayBehaviour_Never:
|
||||||
data->play_now_ = false;
|
data->play_now_ = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PlayBehaviour_IfStopped:
|
case BehaviourSettingsPage::PlayBehaviour_IfStopped:
|
||||||
data->play_now_ = !(app_->player()->GetState() == Engine::Playing);
|
data->play_now_ = !(app_->player()->GetState() == Engine::Playing);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1581,7 +1580,6 @@ void MainWindow::EditTracks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//EnsureEditTagDialogCreated();
|
|
||||||
edit_tag_dialog_->SetSongs(songs, items);
|
edit_tag_dialog_->SetSongs(songs, items);
|
||||||
edit_tag_dialog_->show();
|
edit_tag_dialog_->show();
|
||||||
|
|
||||||
@@ -1625,7 +1623,7 @@ void MainWindow::RenumberTracks() {
|
|||||||
if (song.IsEditable()) {
|
if (song.IsEditable()) {
|
||||||
song.set_track(track);
|
song.set_track(track);
|
||||||
|
|
||||||
TagReaderReply *reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||||
|
|
||||||
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
|
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1632,7 @@ void MainWindow::RenumberTracks() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SongSaveComplete(TagReaderReply *reply,const QPersistentModelIndex &index) {
|
void MainWindow::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &index) {
|
||||||
if (reply->is_successful() && index.isValid()) {
|
if (reply->is_successful() && index.isValid()) {
|
||||||
app_->playlist_manager()->current()->ReloadItems(QList<int>()<< index.row());
|
app_->playlist_manager()->current()->ReloadItems(QList<int>()<< index.row());
|
||||||
}
|
}
|
||||||
@@ -1644,7 +1642,7 @@ void MainWindow::SongSaveComplete(TagReaderReply *reply,const QPersistentModelIn
|
|||||||
void MainWindow::SelectionSetValue() {
|
void MainWindow::SelectionSetValue() {
|
||||||
|
|
||||||
Playlist::Column column = (Playlist::Column)playlist_menu_index_.column();
|
Playlist::Column column = (Playlist::Column)playlist_menu_index_.column();
|
||||||
QVariant column_value =app_->playlist_manager()->current()->data(playlist_menu_index_);
|
QVariant column_value = app_->playlist_manager()->current()->data(playlist_menu_index_);
|
||||||
|
|
||||||
QModelIndexList indexes =ui_->playlist->view()->selectionModel()->selection().indexes();
|
QModelIndexList indexes =ui_->playlist->view()->selectionModel()->selection().indexes();
|
||||||
|
|
||||||
@@ -1656,9 +1654,9 @@ void MainWindow::SelectionSetValue() {
|
|||||||
Song song = app_->playlist_manager()->current()->item_at(row)->Metadata();
|
Song song = app_->playlist_manager()->current()->item_at(row)->Metadata();
|
||||||
|
|
||||||
if (Playlist::set_column_value(song, column, column_value)) {
|
if (Playlist::set_column_value(song, column, column_value)) {
|
||||||
TagReaderReply *reply =TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||||
|
|
||||||
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
|
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)), reply, QPersistentModelIndex(source_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1836,7 +1834,7 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
|
|||||||
break;
|
break;
|
||||||
case CommandlineOptions::UrlList_CreateNew:
|
case CommandlineOptions::UrlList_CreateNew:
|
||||||
data->name_for_new_playlist_ = options.playlist_name();
|
data->name_for_new_playlist_ = options.playlist_name();
|
||||||
ApplyAddBehaviour(AddBehaviour_OpenInNew, data);
|
ApplyAddBehaviour(BehaviourSettingsPage::AddBehaviour_OpenInNew, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2136,7 +2134,6 @@ void MainWindow::ShowTranscodeDialog() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void MainWindow::ShowErrorDialog(const QString &message) {
|
void MainWindow::ShowErrorDialog(const QString &message) {
|
||||||
|
|
||||||
error_dialog_->ShowMessage(message);
|
error_dialog_->ShowMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2331,7 +2328,7 @@ void MainWindow::SearchForCover() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SaveCoverToFile() {
|
void MainWindow::SaveCoverToFile() {
|
||||||
album_cover_choice_controller_->SaveCoverToFile(song_, image_original_);
|
album_cover_choice_controller_->SaveCoverToFileManual(song_, image_original_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::UnsetCover() {
|
void MainWindow::UnsetCover() {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QPersistentModelIndex>
|
#include <QPersistentModelIndex>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -56,6 +55,7 @@
|
|||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
#include "playlist/playlistitem.h"
|
#include "playlist/playlistitem.h"
|
||||||
#include "settings/settingsdialog.h"
|
#include "settings/settingsdialog.h"
|
||||||
|
#include "settings/behavioursettingspage.h"
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
|
|
||||||
@@ -109,27 +109,6 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
Startup_AlwaysHide = 3,
|
Startup_AlwaysHide = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't change the values
|
|
||||||
enum AddBehaviour {
|
|
||||||
AddBehaviour_Append = 1,
|
|
||||||
AddBehaviour_Enqueue = 2,
|
|
||||||
AddBehaviour_Load = 3,
|
|
||||||
AddBehaviour_OpenInNew = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
// Don't change the values
|
|
||||||
enum PlayBehaviour {
|
|
||||||
PlayBehaviour_Never = 1,
|
|
||||||
PlayBehaviour_IfStopped = 2,
|
|
||||||
PlayBehaviour_Always = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Don't change the values
|
|
||||||
enum PlaylistAddBehaviour {
|
|
||||||
PlaylistAddBehaviour_Play = 1,
|
|
||||||
PlaylistAddBehaviour_Enqueue = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetHiddenInTray(bool hidden);
|
void SetHiddenInTray(bool hidden);
|
||||||
void CommandlineOptionsReceived(const CommandlineOptions& options);
|
void CommandlineOptionsReceived(const CommandlineOptions& options);
|
||||||
|
|
||||||
@@ -279,8 +258,8 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ApplyAddBehaviour(AddBehaviour b, MimeData *data) const;
|
void ApplyAddBehaviour(BehaviourSettingsPage::AddBehaviour b, MimeData *data) const;
|
||||||
void ApplyPlayBehaviour(PlayBehaviour b, MimeData *data) const;
|
void ApplyPlayBehaviour(BehaviourSettingsPage::PlayBehaviour b, MimeData *data) const;
|
||||||
|
|
||||||
void CheckFullRescanRevisions();
|
void CheckFullRescanRevisions();
|
||||||
|
|
||||||
@@ -298,8 +277,8 @@ signals:
|
|||||||
Application *app_;
|
Application *app_;
|
||||||
SystemTrayIcon *tray_icon_;
|
SystemTrayIcon *tray_icon_;
|
||||||
OSD *osd_;
|
OSD *osd_;
|
||||||
Lazy<EditTagDialog> edit_tag_dialog_;
|
|
||||||
Lazy<About> about_dialog_;
|
Lazy<About> about_dialog_;
|
||||||
|
Lazy<EditTagDialog> edit_tag_dialog_;
|
||||||
AlbumCoverChoiceController *album_cover_choice_controller_;
|
AlbumCoverChoiceController *album_cover_choice_controller_;
|
||||||
|
|
||||||
GlobalShortcuts *global_shortcuts_;
|
GlobalShortcuts *global_shortcuts_;
|
||||||
@@ -332,7 +311,6 @@ signals:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
InternetSearchView *tidal_search_view_;
|
InternetSearchView *tidal_search_view_;
|
||||||
InternetSearchView *deezer_search_view_;
|
|
||||||
|
|
||||||
QAction *collection_show_all_;
|
QAction *collection_show_all_;
|
||||||
QAction *collection_show_duplicates_;
|
QAction *collection_show_duplicates_;
|
||||||
@@ -371,10 +349,11 @@ signals:
|
|||||||
bool was_maximized_;
|
bool was_maximized_;
|
||||||
int saved_playback_position_;
|
int saved_playback_position_;
|
||||||
Engine::State saved_playback_state_;
|
Engine::State saved_playback_state_;
|
||||||
AddBehaviour doubleclick_addmode_;
|
bool playing_widget_;
|
||||||
PlayBehaviour doubleclick_playmode_;
|
BehaviourSettingsPage::AddBehaviour doubleclick_addmode_;
|
||||||
PlaylistAddBehaviour doubleclick_playlist_addmode_;
|
BehaviourSettingsPage::PlayBehaviour doubleclick_playmode_;
|
||||||
PlayBehaviour menu_playmode_;
|
BehaviourSettingsPage::PlaylistAddBehaviour doubleclick_playlist_addmode_;
|
||||||
|
BehaviourSettingsPage::PlayBehaviour menu_playmode_;
|
||||||
|
|
||||||
Song song_;
|
Song song_;
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
|
|||||||
@@ -225,7 +225,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Amarok::VolumeSlider" name="volume">
|
<widget class="VolumeSlider" name="volume">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@@ -773,9 +773,9 @@
|
|||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>Amarok::VolumeSlider</class>
|
<class>VolumeSlider</class>
|
||||||
<extends>QSlider</extends>
|
<extends>QSlider</extends>
|
||||||
<header>widgets/sliderwidget.h</header>
|
<header>widgets/volumeslider.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>AnalyzerContainer</class>
|
<class>AnalyzerContainer</class>
|
||||||
|
|||||||