Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59622c52ad | ||
|
|
a8e9aba58b | ||
|
|
36563cd1e1 | ||
|
|
072e712f0d | ||
|
|
121a186160 | ||
|
|
15a2ccc21e | ||
|
|
dbd8ea69eb | ||
|
|
8a57356f64 | ||
|
|
c77cb002f3 | ||
|
|
aa83a2b40b | ||
|
|
65b04cac6e | ||
|
|
5e577190a8 | ||
|
|
0143617056 | ||
|
|
a77dde7d3b | ||
|
|
7dcdb7c673 | ||
|
|
6de8eb56cd | ||
|
|
04e272d9bc | ||
|
|
17fe201473 | ||
|
|
25249be37f | ||
|
|
97ec12b5b3 | ||
|
|
246f82bfad | ||
|
|
db5679bbe9 | ||
|
|
feb0e1c45b | ||
|
|
edba837295 | ||
|
|
55882360ef | ||
|
|
6039370ad6 | ||
|
|
2d238c08d3 | ||
|
|
9b337b6a34 | ||
|
|
370db791aa | ||
|
|
9e3c547580 | ||
|
|
ab5d9b62b8 |
12
Changelog
12
Changelog
@@ -2,6 +2,18 @@ Strawberry Music Player
|
|||||||
=======================
|
=======================
|
||||||
ChangeLog
|
ChangeLog
|
||||||
|
|
||||||
|
Version 0.3.2:
|
||||||
|
|
||||||
|
* Fixed search error not shown in Tidal search
|
||||||
|
* Added URL handler for Tidal, now retriving URL's when playing instead of when searching
|
||||||
|
* Fixed bug in pipeline not setting url
|
||||||
|
* Fixed bug setting wrong temporary metadata
|
||||||
|
* Removed device module from windows, since it's not implemented for windows
|
||||||
|
* Added support for both ALSA hw and plughw
|
||||||
|
* Added option to change url stream scheme for Tidal
|
||||||
|
* Added encoding of Tidal token in the source code
|
||||||
|
* Added encoding of Tidal password in the configuration
|
||||||
|
|
||||||
Version 0.3.1:
|
Version 0.3.1:
|
||||||
|
|
||||||
* Added new lyrics provider with lyrics from AudD and API Seeds
|
* Added new lyrics provider with lyrics from AudD and API Seeds
|
||||||
|
|||||||
@@ -1,28 +1,65 @@
|
|||||||
find_program(LSB_RELEASE_EXEC lsb_release)
|
find_program(LSB_RELEASE_EXEC lsb_release)
|
||||||
execute_process(COMMAND ${LSB_RELEASE_EXEC} -is
|
|
||||||
OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
|
|
||||||
if (LSB_RELEASE_EXEC)
|
if (LSB_RELEASE_EXEC)
|
||||||
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -is | tr '[:upper:]' '[:lower:]' | cut -d' ' -f1"
|
||||||
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
|
OUTPUT_VARIABLE DIST_NAME
|
||||||
if (${LSB_RELEASE_ID_SHORT} STREQUAL "openSUSE")
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
set(RPM_DISTRO opensuse CACHE STRING "Suffix of the rpm file")
|
)
|
||||||
add_custom_target(rpm
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | cut -d' ' -f2"
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
|
OUTPUT_VARIABLE DIST_RELEASE
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
|
)
|
||||||
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
|
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
|
||||||
)
|
OUTPUT_VARIABLE DIST_VERSION
|
||||||
endif()
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
if (${LSB_RELEASE_ID_SHORT} STREQUAL "Fedora")
|
)
|
||||||
set(RPM_DISTRO fedora CACHE STRING "Suffix of the rpm file")
|
if (DIST_NAME)
|
||||||
add_custom_target(rpm
|
message(STATUS "Distro Name: ${DIST_NAME}")
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
|
if (DIST_RELEASE)
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
|
message(STATUS "Distro Release: ${DIST_RELEASE}")
|
||||||
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
|
endif()
|
||||||
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
|
if (DIST_VERSION)
|
||||||
)
|
message(STATUS "Distro Version: ${DIST_VERSION}")
|
||||||
|
endif()
|
||||||
|
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
|
||||||
|
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
|
||||||
|
if (${DIST_NAME} STREQUAL "opensuse")
|
||||||
|
if (DIST_RELEASE)
|
||||||
|
if (${DIST_RELEASE} STREQUAL "leap")
|
||||||
|
if (DIST_VERSION)
|
||||||
|
set(RPM_DISTRO "lp${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
|
||||||
|
else()
|
||||||
|
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
|
||||||
|
endif()
|
||||||
|
elseif (${DIST_RELEASE} STREQUAL "tumbleweed")
|
||||||
|
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
|
||||||
|
else ()
|
||||||
|
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
|
||||||
|
endif()
|
||||||
|
add_custom_target(rpm
|
||||||
|
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
|
||||||
|
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
|
||||||
|
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
|
||||||
|
)
|
||||||
|
elseif (${DIST_NAME} STREQUAL "fedora")
|
||||||
|
if (DIST_VERSION)
|
||||||
|
set(RPM_DISTRO "${DIST_NAME}${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
|
||||||
|
else ()
|
||||||
|
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
|
||||||
|
endif()
|
||||||
|
add_custom_target(rpm
|
||||||
|
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
|
||||||
|
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
|
||||||
|
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
|
||||||
|
endif()
|
||||||
|
message(STATUS "RPM Suffix: ${RPM_DISTRO}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||||
set(STRAWBERRY_VERSION_MINOR 3)
|
set(STRAWBERRY_VERSION_MINOR 3)
|
||||||
set(STRAWBERRY_VERSION_PATCH 1)
|
set(STRAWBERRY_VERSION_PATCH 2)
|
||||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||||
|
|
||||||
set(INCLUDE_GIT_REVISION OFF)
|
set(INCLUDE_GIT_REVISION OFF)
|
||||||
|
|||||||
8
dist/CMakeLists.txt
vendored
8
dist/CMakeLists.txt
vendored
@@ -2,12 +2,16 @@ execute_process(COMMAND env LC_ALL="en_US.utf8" date "+%a %b %d %Y" OUTPUT_VARIA
|
|||||||
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh @ONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec @ONLY)
|
if (RPM_DISTRO)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec @ONLY)
|
||||||
|
endif()
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi @ONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug-64.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug-64.nsi @ONLY)
|
||||||
|
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
install(FILES ../data/icons/48x48/strawberry.png DESTINATION share/icons/hicolor/48x48/apps/)
|
install(FILES ../data/icons/48x48/strawberry.png DESTINATION share/icons/hicolor/48x48/apps/)
|
||||||
|
|||||||
18
dist/scripts/maketarball.sh.in
vendored
18
dist/scripts/maketarball.sh.in
vendored
@@ -16,12 +16,14 @@ echo "Creating $name-$version.tar.xz..."
|
|||||||
rm -f "$name-$version.tar.xz"
|
rm -f "$name-$version.tar.xz"
|
||||||
tar -cJf $name-$version.tar.xz \
|
tar -cJf $name-$version.tar.xz \
|
||||||
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
||||||
--exclude "*.tar" \
|
--exclude="*.tar" \
|
||||||
--exclude "*.tar.*" \
|
--exclude="*.tar.*" \
|
||||||
--exclude "*.bz" \
|
--exclude="*.bz" \
|
||||||
--exclude "*.bz2" \
|
--exclude="*.bz2" \
|
||||||
--exclude "*.xz" \
|
--exclude="*.xz" \
|
||||||
--exclude ".directory" \
|
--exclude=".directory" \
|
||||||
--exclude "$root/CMakeLists.txt.user" \
|
--exclude="*.spec" \
|
||||||
--exclude "$root/build" \
|
--exclude="*.nsi" \
|
||||||
|
--exclude="$root/CMakeLists.txt.user" \
|
||||||
|
--exclude="$root/build" \
|
||||||
"$root"
|
"$root"
|
||||||
|
|||||||
445
dist/windows/strawberry-64.nsi.in
vendored
Normal file
445
dist/windows/strawberry-64.nsi.in
vendored
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
!define PRODUCT_NAME "Strawberry"
|
||||||
|
!define PRODUCT_PUBLISHER "Strawberry"
|
||||||
|
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
|
||||||
|
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
|
||||||
|
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
|
||||||
|
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
|
||||||
|
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||||
|
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||||
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
|
||||||
|
|
||||||
|
; Set Application Capabilities info
|
||||||
|
!define CAPABILITIES_NAME "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_LOCAL_NAME "Strawberry"
|
||||||
|
!define CAPABILITIES_PROGID "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
|
||||||
|
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
|
||||||
|
!define CAPABILITIES_REINSTALL "Command to reinstall"
|
||||||
|
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
|
||||||
|
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
|
||||||
|
|
||||||
|
SetCompressor /SOLID lzma
|
||||||
|
!addplugindir nsisplugins
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
!include "FileAssociation.nsh"
|
||||||
|
!include "Capabilities.nsh"
|
||||||
|
|
||||||
|
!define MUI_ICON "strawberry.ico"
|
||||||
|
|
||||||
|
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||||
|
;!define MUI_FINISHPAGE_RUN
|
||||||
|
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
|
||||||
|
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
|
||||||
|
|
||||||
|
; Installer pages
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
; Uninstaller pages
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
!insertmacro MUI_UNPAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||||
|
|
||||||
|
Name "${PRODUCT_NAME}"
|
||||||
|
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Release-x64.exe"
|
||||||
|
InstallDir "${PRODUCT_INSTALL_DIR}"
|
||||||
|
|
||||||
|
; Get the path where Strawberry was installed previously and set it as default path
|
||||||
|
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||||
|
|
||||||
|
ShowInstDetails show
|
||||||
|
ShowUnInstDetails show
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
;RequestExecutionLevel user
|
||||||
|
|
||||||
|
; Check for previous installation, and call the uninstaller if any
|
||||||
|
Function CheckPreviousInstall
|
||||||
|
|
||||||
|
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||||
|
StrCmp $R0 "" done
|
||||||
|
|
||||||
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||||
|
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
|
||||||
|
previous version or `Cancel` to cancel this upgrade." \
|
||||||
|
IDOK uninst
|
||||||
|
Abort
|
||||||
|
; Run the uninstaller
|
||||||
|
uninst:
|
||||||
|
ClearErrors
|
||||||
|
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function .onInit
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGDLL_DISPLAY
|
||||||
|
|
||||||
|
Call CheckPreviousInstall
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
;Function RunStrawberry
|
||||||
|
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
|
||||||
|
;FunctionEnd
|
||||||
|
|
||||||
|
Section "Delete old files" oldfiles
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Strawberry" Strawberry
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
File "strawberry.exe"
|
||||||
|
File "strawberry-tagreader.exe"
|
||||||
|
File "strawberry.ico"
|
||||||
|
|
||||||
|
File "libbz2.dll"
|
||||||
|
File "libcdio-16.dll"
|
||||||
|
File "libchromaprint.dll"
|
||||||
|
File "libcrypto-1_1-x64.dll"
|
||||||
|
File "libfaad-2.dll"
|
||||||
|
File "libffi-6.dll"
|
||||||
|
File "libFLAC-8.dll"
|
||||||
|
File "libfreetype-6.dll"
|
||||||
|
File "libgcc_s_seh-1.dll"
|
||||||
|
File "libgio-2.0-0.dll"
|
||||||
|
File "libglib-2.0-0.dll"
|
||||||
|
File "libgmodule-2.0-0.dll"
|
||||||
|
File "libgobject-2.0-0.dll"
|
||||||
|
File "libgstapp-1.0-0.dll"
|
||||||
|
File "libgstaudio-1.0-0.dll"
|
||||||
|
File "libgstbase-1.0-0.dll"
|
||||||
|
File "libgstfft-1.0-0.dll"
|
||||||
|
File "libgstpbutils-1.0-0.dll"
|
||||||
|
File "libgstreamer-1.0-0.dll"
|
||||||
|
File "libgstriff-1.0-0.dll"
|
||||||
|
File "libgstrtp-1.0-0.dll"
|
||||||
|
File "libgstrtsp-1.0-0.dll"
|
||||||
|
File "libgstsdp-1.0-0.dll"
|
||||||
|
File "libgsttag-1.0-0.dll"
|
||||||
|
File "libgstvideo-1.0-0.dll"
|
||||||
|
File "libgstnet-1.0-0.dll"
|
||||||
|
File "libharfbuzz-0.dll"
|
||||||
|
File "libiconv-2.dll"
|
||||||
|
File "libintl-8.dll"
|
||||||
|
File "libjpeg-9.dll"
|
||||||
|
File "liblastfm5.dll"
|
||||||
|
File "libmp3lame-0.dll"
|
||||||
|
File "libogg-0.dll"
|
||||||
|
File "libopus-0.dll"
|
||||||
|
File "libpcre-1.dll"
|
||||||
|
File "libpcre2-16-0.dll"
|
||||||
|
File "libpng16-16.dll"
|
||||||
|
File "libprotobuf-15.dll"
|
||||||
|
File "libspeex-1.dll"
|
||||||
|
File "libsqlite3-0.dll"
|
||||||
|
File "libssl-1_1-x64.dll"
|
||||||
|
File "libstdc++-6.dll"
|
||||||
|
File "libtag.dll"
|
||||||
|
File "libvorbis-0.dll"
|
||||||
|
File "libvorbisenc-2.dll"
|
||||||
|
File "libwavpack-1.dll"
|
||||||
|
File "libwinpthread-1.dll"
|
||||||
|
File "Qt5Concurrent.dll"
|
||||||
|
File "Qt5Core.dll"
|
||||||
|
File "Qt5Gui.dll"
|
||||||
|
File "Qt5Network.dll"
|
||||||
|
File "Qt5Sql.dll"
|
||||||
|
File "Qt5Widgets.dll"
|
||||||
|
File "Qt5Xml.dll"
|
||||||
|
File "Qt5WinExtras.dll"
|
||||||
|
File "zlib1.dll"
|
||||||
|
;File "libmpcdec-5.dll"
|
||||||
|
;File "libtheora-0.dll"
|
||||||
|
File "libfftw3-3.dll"
|
||||||
|
File "libxml2-2.dll"
|
||||||
|
File "libsoup-2.4-1.dll"
|
||||||
|
File "liblzma-5.dll"
|
||||||
|
|
||||||
|
; Register Strawberry with Default Programs
|
||||||
|
Var /GLOBAL AppIcon
|
||||||
|
Var /GLOBAL AppExe
|
||||||
|
StrCpy $AppExe "$INSTDIR\strawberry.exe"
|
||||||
|
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
|
||||||
|
|
||||||
|
${RegisterCapabilities}
|
||||||
|
|
||||||
|
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
|
||||||
|
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
|
||||||
|
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
|
||||||
|
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
|
||||||
|
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
|
||||||
|
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
|
||||||
|
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
|
||||||
|
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
|
||||||
|
|
||||||
|
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
|
||||||
|
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
|
||||||
|
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
|
||||||
|
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
|
||||||
|
|
||||||
|
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
|
||||||
|
|
||||||
|
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt Platforms" platforms
|
||||||
|
SetOutPath "$INSTDIR\platforms"
|
||||||
|
File "/oname=qwindows.dll" "platforms\qwindows.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt SQL Drivers" sqldrivers
|
||||||
|
SetOutPath "$INSTDIR\sqldrivers"
|
||||||
|
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt image format plugins" imageformats
|
||||||
|
SetOutPath "$INSTDIR\imageformats"
|
||||||
|
File "/oname=qgif.dll" "imageformats\qgif.dll"
|
||||||
|
File "/oname=qico.dll" "imageformats\qico.dll"
|
||||||
|
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Gstreamer plugins" gstreamer-plugins
|
||||||
|
SetOutPath "$INSTDIR\gstreamer-plugins"
|
||||||
|
|
||||||
|
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
||||||
|
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
|
||||||
|
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
|
||||||
|
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
|
||||||
|
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
|
||||||
|
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
|
||||||
|
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
|
||||||
|
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
|
||||||
|
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
|
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
||||||
|
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
||||||
|
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||||
|
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
|
||||||
|
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
|
||||||
|
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
||||||
|
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||||
|
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||||
|
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
||||||
|
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
||||||
|
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
|
||||||
|
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
|
||||||
|
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
|
||||||
|
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
|
||||||
|
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
|
||||||
|
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
|
||||||
|
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
|
||||||
|
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
|
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
||||||
|
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
||||||
|
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||||
|
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
||||||
|
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
||||||
|
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
|
||||||
|
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
|
||||||
|
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
|
||||||
|
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Start menu items" startmenu
|
||||||
|
; Create Start Menu folders and shortcuts.
|
||||||
|
SetShellVarContext all
|
||||||
|
|
||||||
|
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Uninstaller"
|
||||||
|
; Create uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
|
||||||
|
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
|
||||||
|
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Uninstall"
|
||||||
|
; Kill strawberry.exe if it's running
|
||||||
|
; This calling convention is retarded...
|
||||||
|
;StrCpy $0 "strawberry.exe"
|
||||||
|
;KillProc::FindProcesses
|
||||||
|
;StrCmp $1 "-1" wooops
|
||||||
|
|
||||||
|
;StrCmp $0 "0" completed
|
||||||
|
|
||||||
|
;DetailPrint "Killing running strawberry.exe..."
|
||||||
|
|
||||||
|
;StrCpy $0 "strawberry.exe"
|
||||||
|
;KillProc::KillProcesses
|
||||||
|
;StrCmp $1 "-1" wooops
|
||||||
|
|
||||||
|
;Sleep 2000
|
||||||
|
;Goto completed
|
||||||
|
|
||||||
|
;wooops:
|
||||||
|
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
|
||||||
|
;Abort
|
||||||
|
|
||||||
|
;completed:
|
||||||
|
|
||||||
|
; Delete all the files
|
||||||
|
|
||||||
|
Delete "$INSTDIR\strawberry.ico"
|
||||||
|
Delete "$INSTDIR\strawberry.exe"
|
||||||
|
Delete "$INSTDIR\strawberry-tagreader.exe"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\libbz2.dll"
|
||||||
|
Delete "$INSTDIR\libcdio-16.dll"
|
||||||
|
Delete "$INSTDIR\libchromaprint.dll"
|
||||||
|
Delete "$INSTDIR\libcrypto-1_1.dll"
|
||||||
|
Delete "$INSTDIR\libfaad-2.dll"
|
||||||
|
Delete "$INSTDIR\libffi-6.dll"
|
||||||
|
Delete "$INSTDIR\libFLAC-8.dll"
|
||||||
|
Delete "$INSTDIR\libfreetype-6.dll"
|
||||||
|
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||||
|
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgobject-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstapp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstbase-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstfft-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstriff-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgsttag-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstnet-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libharfbuzz-0.dll"
|
||||||
|
Delete "$INSTDIR\libiconv-2.dll"
|
||||||
|
Delete "$INSTDIR\libintl-8.dll"
|
||||||
|
Delete "$INSTDIR\libjpeg-9.dll"
|
||||||
|
Delete "$INSTDIR\liblastfm5.dll"
|
||||||
|
Delete "$INSTDIR\libmp3lame-0.dll"
|
||||||
|
Delete "$INSTDIR\libogg-0.dll"
|
||||||
|
Delete "$INSTDIR\libopus-0.dll"
|
||||||
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
|
Delete "$INSTDIR\libprotobuf-15.dll"
|
||||||
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
|
Delete "$INSTDIR\libssl-1_1.dll"
|
||||||
|
Delete "$INSTDIR\libstdc++-6.dll"
|
||||||
|
Delete "$INSTDIR\libtag.dll"
|
||||||
|
Delete "$INSTDIR\libvorbis-0.dll"
|
||||||
|
Delete "$INSTDIR\libvorbisenc-2.dll"
|
||||||
|
Delete "$INSTDIR\libwavpack-1.dll"
|
||||||
|
Delete "$INSTDIR\libwinpthread-1.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Concurrent.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Core.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Gui.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Network.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Sql.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Widgets.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Xml.dll"
|
||||||
|
Delete "$INSTDIR\Qt5WinExtras.dll"
|
||||||
|
Delete "$INSTDIR\zlib1.dll"
|
||||||
|
;Delete "$INSTDIR\libmpcdec-5.dll"
|
||||||
|
;Delete "$INSTDIR\libtheora-0.dll"
|
||||||
|
Delete "$INSTDIR\libfftw3-3.dll"
|
||||||
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qico.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
; Remove the installation folders.
|
||||||
|
RMDir "$INSTDIR\platforms"
|
||||||
|
RMDir "$INSTDIR\sqldrivers"
|
||||||
|
RMDir "$INSTDIR\imageformats"
|
||||||
|
RMDir "$INSTDIR\gstreamer-plugins"
|
||||||
|
RMDir "$INSTDIR\xine-plugins"
|
||||||
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
|
; Remove the Shortcuts
|
||||||
|
SetShellVarContext all
|
||||||
|
|
||||||
|
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
|
||||||
|
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
|
||||||
|
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||||
|
|
||||||
|
; Remove the entry from 'installed programs list'
|
||||||
|
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
|
||||||
|
|
||||||
|
; Unregister from Default Programs
|
||||||
|
${UnRegisterCapabilities}
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
505
dist/windows/strawberry-debug-64.nsi.in
vendored
Normal file
505
dist/windows/strawberry-debug-64.nsi.in
vendored
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
!define PRODUCT_NAME "Strawberry"
|
||||||
|
!define PRODUCT_PUBLISHER "Strawberry"
|
||||||
|
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
|
||||||
|
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
|
||||||
|
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
|
||||||
|
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
|
||||||
|
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||||
|
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||||
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
|
||||||
|
|
||||||
|
; Set Application Capabilities info
|
||||||
|
!define CAPABILITIES_NAME "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_LOCAL_NAME "Strawberry"
|
||||||
|
!define CAPABILITIES_PROGID "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
|
||||||
|
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
|
||||||
|
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
|
||||||
|
!define CAPABILITIES_REINSTALL "Command to reinstall"
|
||||||
|
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
|
||||||
|
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
|
||||||
|
|
||||||
|
SetCompressor /SOLID lzma
|
||||||
|
!addplugindir nsisplugins
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
!include "FileAssociation.nsh"
|
||||||
|
!include "Capabilities.nsh"
|
||||||
|
|
||||||
|
!define MUI_ICON "strawberry.ico"
|
||||||
|
|
||||||
|
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||||
|
;!define MUI_FINISHPAGE_RUN
|
||||||
|
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
|
||||||
|
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
|
||||||
|
|
||||||
|
; Installer pages
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
; Uninstaller pages
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
!insertmacro MUI_UNPAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||||
|
|
||||||
|
Name "${PRODUCT_NAME}"
|
||||||
|
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
|
||||||
|
InstallDir "${PRODUCT_INSTALL_DIR}"
|
||||||
|
|
||||||
|
; Get the path where Strawberry was installed previously and set it as default path
|
||||||
|
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||||
|
|
||||||
|
ShowInstDetails show
|
||||||
|
ShowUnInstDetails show
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
;RequestExecutionLevel user
|
||||||
|
|
||||||
|
; Check for previous installation, and call the uninstaller if any
|
||||||
|
Function CheckPreviousInstall
|
||||||
|
|
||||||
|
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
|
||||||
|
StrCmp $R0 "" done
|
||||||
|
|
||||||
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||||
|
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
|
||||||
|
previous version or `Cancel` to cancel this upgrade." \
|
||||||
|
IDOK uninst
|
||||||
|
Abort
|
||||||
|
; Run the uninstaller
|
||||||
|
uninst:
|
||||||
|
ClearErrors
|
||||||
|
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function .onInit
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGDLL_DISPLAY
|
||||||
|
|
||||||
|
Call CheckPreviousInstall
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
;Function RunStrawberry
|
||||||
|
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
|
||||||
|
;FunctionEnd
|
||||||
|
|
||||||
|
Section "Delete old files" oldfiles
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Strawberry" Strawberry
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
File "strawberry.exe"
|
||||||
|
File "strawberry-tagreader.exe"
|
||||||
|
File "strawberry.ico"
|
||||||
|
|
||||||
|
File "libbz2.dll"
|
||||||
|
File "libcdio-16.dll"
|
||||||
|
File "libchromaprint.dll"
|
||||||
|
File "libcrypto-1_1-x64.dll"
|
||||||
|
File "libfaad-2.dll"
|
||||||
|
File "libffi-6.dll"
|
||||||
|
File "libFLAC-8.dll"
|
||||||
|
File "libfreetype-6.dll"
|
||||||
|
File "libgcc_s_seh-1.dll"
|
||||||
|
File "libgio-2.0-0.dll"
|
||||||
|
File "libglib-2.0-0.dll"
|
||||||
|
File "libgmodule-2.0-0.dll"
|
||||||
|
File "libgobject-2.0-0.dll"
|
||||||
|
File "libgstapp-1.0-0.dll"
|
||||||
|
File "libgstaudio-1.0-0.dll"
|
||||||
|
File "libgstbase-1.0-0.dll"
|
||||||
|
File "libgstfft-1.0-0.dll"
|
||||||
|
File "libgstpbutils-1.0-0.dll"
|
||||||
|
File "libgstreamer-1.0-0.dll"
|
||||||
|
File "libgstriff-1.0-0.dll"
|
||||||
|
File "libgstrtp-1.0-0.dll"
|
||||||
|
File "libgstrtsp-1.0-0.dll"
|
||||||
|
File "libgstsdp-1.0-0.dll"
|
||||||
|
File "libgsttag-1.0-0.dll"
|
||||||
|
File "libgstvideo-1.0-0.dll"
|
||||||
|
File "libgstnet-1.0-0.dll"
|
||||||
|
File "libharfbuzz-0.dll"
|
||||||
|
File "libiconv-2.dll"
|
||||||
|
File "libintl-8.dll"
|
||||||
|
File "libjpeg-9.dll"
|
||||||
|
File "liblastfm5.dll"
|
||||||
|
File "libmp3lame-0.dll"
|
||||||
|
File "libogg-0.dll"
|
||||||
|
File "libopus-0.dll"
|
||||||
|
File "libpcre-1.dll"
|
||||||
|
File "libpcre2-16-0.dll"
|
||||||
|
File "libpng16-16.dll"
|
||||||
|
File "libprotobuf-15.dll"
|
||||||
|
File "libspeex-1.dll"
|
||||||
|
File "libsqlite3-0.dll"
|
||||||
|
File "libssl-1_1-x64.dll"
|
||||||
|
File "libstdc++-6.dll"
|
||||||
|
File "libtag.dll"
|
||||||
|
File "libvorbis-0.dll"
|
||||||
|
File "libvorbisenc-2.dll"
|
||||||
|
File "libwavpack-1.dll"
|
||||||
|
File "libwinpthread-1.dll"
|
||||||
|
File "Qt5Concurrent.dll"
|
||||||
|
File "Qt5Core.dll"
|
||||||
|
File "Qt5Gui.dll"
|
||||||
|
File "Qt5Network.dll"
|
||||||
|
File "Qt5Sql.dll"
|
||||||
|
File "Qt5Widgets.dll"
|
||||||
|
File "Qt5Xml.dll"
|
||||||
|
File "Qt5WinExtras.dll"
|
||||||
|
File "zlib1.dll"
|
||||||
|
File "libxine-2.dll"
|
||||||
|
File "libmpcdec-5.dll"
|
||||||
|
File "libtheora-0.dll"
|
||||||
|
File "libfftw3-3.dll"
|
||||||
|
File "libxml2-2.dll"
|
||||||
|
File "libsoup-2.4-1.dll"
|
||||||
|
File "liblzma-5.dll"
|
||||||
|
|
||||||
|
; Register Strawberry with Default Programs
|
||||||
|
Var /GLOBAL AppIcon
|
||||||
|
Var /GLOBAL AppExe
|
||||||
|
StrCpy $AppExe "$INSTDIR\strawberry.exe"
|
||||||
|
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
|
||||||
|
|
||||||
|
${RegisterCapabilities}
|
||||||
|
|
||||||
|
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
|
||||||
|
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
|
||||||
|
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
|
||||||
|
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
|
||||||
|
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
|
||||||
|
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
|
||||||
|
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
|
||||||
|
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
|
||||||
|
|
||||||
|
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
|
||||||
|
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
|
||||||
|
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
|
||||||
|
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
|
||||||
|
|
||||||
|
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
|
||||||
|
|
||||||
|
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
|
||||||
|
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt Platforms" platforms
|
||||||
|
SetOutPath "$INSTDIR\platforms"
|
||||||
|
File "/oname=qwindows.dll" "platforms\qwindows.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt SQL Drivers" sqldrivers
|
||||||
|
SetOutPath "$INSTDIR\sqldrivers"
|
||||||
|
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Qt image format plugins" imageformats
|
||||||
|
SetOutPath "$INSTDIR\imageformats"
|
||||||
|
File "/oname=qgif.dll" "imageformats\qgif.dll"
|
||||||
|
File "/oname=qico.dll" "imageformats\qico.dll"
|
||||||
|
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Gstreamer plugins" gstreamer-plugins
|
||||||
|
SetOutPath "$INSTDIR\gstreamer-plugins"
|
||||||
|
|
||||||
|
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
|
||||||
|
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
|
||||||
|
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
|
||||||
|
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
|
||||||
|
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
|
||||||
|
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
|
||||||
|
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
|
||||||
|
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
|
||||||
|
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
|
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
|
||||||
|
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
|
||||||
|
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
|
||||||
|
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
|
||||||
|
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
|
||||||
|
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
|
||||||
|
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
|
||||||
|
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
|
||||||
|
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
|
||||||
|
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
|
||||||
|
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
|
||||||
|
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
|
||||||
|
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
|
||||||
|
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
|
||||||
|
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
|
||||||
|
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
|
||||||
|
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
|
||||||
|
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
|
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
|
||||||
|
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
|
||||||
|
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
|
||||||
|
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
|
||||||
|
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
|
||||||
|
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
|
||||||
|
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
|
||||||
|
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
|
||||||
|
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Xine plugins" xine-plugins
|
||||||
|
SetOutPath "$INSTDIR\xine-plugins"
|
||||||
|
File "/oname=xineplug_ao_out_directx2.dll" "xine-plugins\xineplug_ao_out_directx2.dll"
|
||||||
|
File "/oname=xineplug_ao_out_directx.dll" "xine-plugins\xineplug_ao_out_directx.dll"
|
||||||
|
File "/oname=xineplug_decode_dts.dll" "xine-plugins\xineplug_decode_dts.dll"
|
||||||
|
File "/oname=xineplug_decode_dvaudio.dll" "xine-plugins\xineplug_decode_dvaudio.dll"
|
||||||
|
File "/oname=xineplug_decode_faad.dll" "xine-plugins\xineplug_decode_faad.dll"
|
||||||
|
File "/oname=xineplug_decode_gsm610.dll" "xine-plugins\xineplug_decode_gsm610.dll"
|
||||||
|
File "/oname=xineplug_decode_lpcm.dll" "xine-plugins\xineplug_decode_lpcm.dll"
|
||||||
|
File "/oname=xineplug_decode_mad.dll" "xine-plugins\xineplug_decode_mad.dll"
|
||||||
|
File "/oname=xineplug_decode_mpc.dll" "xine-plugins\xineplug_decode_mpc.dll"
|
||||||
|
File "/oname=xineplug_decode_mpeg2.dll" "xine-plugins\xineplug_decode_mpeg2.dll"
|
||||||
|
File "/oname=xineplug_dmx_asf.dll" "xine-plugins\xineplug_dmx_asf.dll"
|
||||||
|
File "/oname=xineplug_dmx_audio.dll" "xine-plugins\xineplug_dmx_audio.dll"
|
||||||
|
File "/oname=xineplug_dmx_playlist.dll" "xine-plugins\xineplug_dmx_playlist.dll"
|
||||||
|
File "/oname=xineplug_dmx_slave.dll" "xine-plugins\xineplug_dmx_slave.dll"
|
||||||
|
File "/oname=xineplug_flac.dll" "xine-plugins\xineplug_flac.dll"
|
||||||
|
File "/oname=xineplug_wavpack.dll" "xine-plugins\xineplug_wavpack.dll"
|
||||||
|
File "/oname=xineplug_xiph.dll" "xine-plugins\xineplug_xiph.dll"
|
||||||
|
File "/oname=xineplug_inp_cdda.dll" "xine-plugins\xineplug_inp_cdda.dll"
|
||||||
|
|
||||||
|
File "/oname=xineplug_post_audio_filters.dll" "xine-plugins\xineplug_post_audio_filters.dll"
|
||||||
|
File "/oname=xineplug_post_goom.dll" "xine-plugins\xineplug_post_goom.dll"
|
||||||
|
File "/oname=xineplug_post_mosaico.dll" "xine-plugins\xineplug_post_mosaico.dll"
|
||||||
|
File "/oname=xineplug_post_planar.dll" "xine-plugins\xineplug_post_planar.dll"
|
||||||
|
File "/oname=xineplug_post_switch.dll" "xine-plugins\xineplug_post_switch.dll"
|
||||||
|
File "/oname=xineplug_post_tvtime.dll" "xine-plugins\xineplug_post_tvtime.dll"
|
||||||
|
File "/oname=xineplug_post_visualizations.dll" "xine-plugins\xineplug_post_visualizations.dll"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Start menu items" startmenu
|
||||||
|
; Create Start Menu folders and shortcuts.
|
||||||
|
SetShellVarContext all
|
||||||
|
|
||||||
|
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Uninstaller"
|
||||||
|
; Create uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
|
||||||
|
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
|
||||||
|
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||||
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Uninstall"
|
||||||
|
; Kill strawberry.exe if it's running
|
||||||
|
; This calling convention is retarded...
|
||||||
|
;StrCpy $0 "strawberry.exe"
|
||||||
|
;KillProc::FindProcesses
|
||||||
|
;StrCmp $1 "-1" wooops
|
||||||
|
|
||||||
|
;StrCmp $0 "0" completed
|
||||||
|
|
||||||
|
;DetailPrint "Killing running strawberry.exe..."
|
||||||
|
|
||||||
|
;StrCpy $0 "strawberry.exe"
|
||||||
|
;KillProc::KillProcesses
|
||||||
|
;StrCmp $1 "-1" wooops
|
||||||
|
|
||||||
|
;Sleep 2000
|
||||||
|
;Goto completed
|
||||||
|
|
||||||
|
;wooops:
|
||||||
|
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
|
||||||
|
;Abort
|
||||||
|
|
||||||
|
;completed:
|
||||||
|
|
||||||
|
; Delete all the files
|
||||||
|
|
||||||
|
Delete "$INSTDIR\strawberry.ico"
|
||||||
|
Delete "$INSTDIR\strawberry.exe"
|
||||||
|
Delete "$INSTDIR\strawberry-tagreader.exe"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\libbz2.dll"
|
||||||
|
Delete "$INSTDIR\libcdio-16.dll"
|
||||||
|
Delete "$INSTDIR\libchromaprint.dll"
|
||||||
|
Delete "$INSTDIR\libcrypto-1_1.dll"
|
||||||
|
Delete "$INSTDIR\libfaad-2.dll"
|
||||||
|
Delete "$INSTDIR\libffi-6.dll"
|
||||||
|
Delete "$INSTDIR\libFLAC-8.dll"
|
||||||
|
Delete "$INSTDIR\libfreetype-6.dll"
|
||||||
|
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||||
|
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgobject-2.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstapp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstbase-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstfft-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstriff-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgsttag-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libgstnet-1.0-0.dll"
|
||||||
|
Delete "$INSTDIR\libharfbuzz-0.dll"
|
||||||
|
Delete "$INSTDIR\libiconv-2.dll"
|
||||||
|
Delete "$INSTDIR\libintl-8.dll"
|
||||||
|
Delete "$INSTDIR\libjpeg-9.dll"
|
||||||
|
Delete "$INSTDIR\liblastfm5.dll"
|
||||||
|
Delete "$INSTDIR\libmp3lame-0.dll"
|
||||||
|
Delete "$INSTDIR\libogg-0.dll"
|
||||||
|
Delete "$INSTDIR\libopus-0.dll"
|
||||||
|
Delete "$INSTDIR\libpcre-1.dll"
|
||||||
|
Delete "$INSTDIR\libpcre2-16-0.dll"
|
||||||
|
Delete "$INSTDIR\libpng16-16.dll"
|
||||||
|
Delete "$INSTDIR\libprotobuf-15.dll"
|
||||||
|
Delete "$INSTDIR\libspeex-1.dll"
|
||||||
|
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||||
|
Delete "$INSTDIR\libssl-1_1.dll"
|
||||||
|
Delete "$INSTDIR\libstdc++-6.dll"
|
||||||
|
Delete "$INSTDIR\libtag.dll"
|
||||||
|
Delete "$INSTDIR\libvorbis-0.dll"
|
||||||
|
Delete "$INSTDIR\libvorbisenc-2.dll"
|
||||||
|
Delete "$INSTDIR\libwavpack-1.dll"
|
||||||
|
Delete "$INSTDIR\libwinpthread-1.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Concurrent.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Core.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Gui.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Network.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Sql.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Widgets.dll"
|
||||||
|
Delete "$INSTDIR\Qt5Xml.dll"
|
||||||
|
Delete "$INSTDIR\Qt5WinExtras.dll"
|
||||||
|
Delete "$INSTDIR\zlib1.dll"
|
||||||
|
Delete "$INSTDIR\libxine-2.dll"
|
||||||
|
Delete "$INSTDIR\libmpcdec-5.dll"
|
||||||
|
Delete "$INSTDIR\libtheora-0.dll"
|
||||||
|
Delete "$INSTDIR\libfftw3-3.dll"
|
||||||
|
Delete "$INSTDIR\libxml2-2.dll"
|
||||||
|
Delete "$INSTDIR\libsoup-2.4-1.dll"
|
||||||
|
Delete "$INSTDIR\liblzma-5.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||||
|
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qico.dll"
|
||||||
|
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
|
||||||
|
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx2.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_dts.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_dvaudio.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_faad.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_gsm610.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_lpcm.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_mad.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpc.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpeg2.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_dmx_asf.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_dmx_audio.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_dmx_playlist.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_dmx_slave.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_flac.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_wavpack.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_xiph.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_inp_cdda.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_audio_filters.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_goom.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_mosaico.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_planar.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_switch.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_tvtime.dll"
|
||||||
|
Delete "$INSTDIR\xine-plugins\xineplug_post_visualizations.dll"
|
||||||
|
|
||||||
|
Delete "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
; Remove the installation folders.
|
||||||
|
RMDir "$INSTDIR\platforms"
|
||||||
|
RMDir "$INSTDIR\sqldrivers"
|
||||||
|
RMDir "$INSTDIR\imageformats"
|
||||||
|
RMDir "$INSTDIR\gstreamer-plugins"
|
||||||
|
RMDir "$INSTDIR\xine-plugins"
|
||||||
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
|
; Remove the Shortcuts
|
||||||
|
SetShellVarContext all
|
||||||
|
|
||||||
|
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
|
||||||
|
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
|
||||||
|
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||||
|
|
||||||
|
; Remove the entry from 'installed programs list'
|
||||||
|
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
|
||||||
|
|
||||||
|
; Unregister from Default Programs
|
||||||
|
${UnRegisterCapabilities}
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
2
dist/windows/strawberry.nsi.in
vendored
2
dist/windows/strawberry.nsi.in
vendored
@@ -48,7 +48,7 @@ SetCompressor /SOLID lzma
|
|||||||
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||||
|
|
||||||
Name "${PRODUCT_NAME}"
|
Name "${PRODUCT_NAME}"
|
||||||
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}.exe"
|
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Release.exe"
|
||||||
InstallDir "${PRODUCT_INSTALL_DIR}"
|
InstallDir "${PRODUCT_INSTALL_DIR}"
|
||||||
|
|
||||||
; Get the path where Strawberry was installed previously and set it as default path
|
; Get the path where Strawberry was installed previously and set it as default path
|
||||||
|
|||||||
@@ -192,8 +192,14 @@ set(SOURCES
|
|||||||
covermanager/coverfromurldialog.cpp
|
covermanager/coverfromurldialog.cpp
|
||||||
covermanager/musicbrainzcoverprovider.cpp
|
covermanager/musicbrainzcoverprovider.cpp
|
||||||
covermanager/discogscoverprovider.cpp
|
covermanager/discogscoverprovider.cpp
|
||||||
#covermanager/amazoncoverprovider.cpp
|
|
||||||
|
lyrics/lyricsproviders.cpp
|
||||||
|
lyrics/lyricsprovider.cpp
|
||||||
|
lyrics/lyricsfetcher.cpp
|
||||||
|
lyrics/lyricsfetchersearch.cpp
|
||||||
|
lyrics/auddlyricsprovider.cpp
|
||||||
|
lyrics/apiseedslyricsprovider.cpp
|
||||||
|
|
||||||
settings/settingsdialog.cpp
|
settings/settingsdialog.cpp
|
||||||
settings/settingspage.cpp
|
settings/settingspage.cpp
|
||||||
settings/behavioursettingspage.cpp
|
settings/behavioursettingspage.cpp
|
||||||
@@ -247,16 +253,6 @@ set(SOURCES
|
|||||||
globalshortcuts/gnomeglobalshortcutbackend.cpp
|
globalshortcuts/gnomeglobalshortcutbackend.cpp
|
||||||
globalshortcuts/qxtglobalshortcutbackend.cpp
|
globalshortcuts/qxtglobalshortcutbackend.cpp
|
||||||
globalshortcuts/globalshortcutgrabber.cpp
|
globalshortcuts/globalshortcutgrabber.cpp
|
||||||
|
|
||||||
device/connecteddevice.cpp
|
|
||||||
device/devicedatabasebackend.cpp
|
|
||||||
device/devicelister.cpp
|
|
||||||
device/devicemanager.cpp
|
|
||||||
device/deviceproperties.cpp
|
|
||||||
device/devicestatefiltermodel.cpp
|
|
||||||
device/deviceview.cpp
|
|
||||||
device/deviceviewcontainer.cpp
|
|
||||||
device/filesystemdevice.cpp
|
|
||||||
|
|
||||||
internet/internetmodel.cpp
|
internet/internetmodel.cpp
|
||||||
internet/internetservice.cpp
|
internet/internetservice.cpp
|
||||||
@@ -268,13 +264,7 @@ set(SOURCES
|
|||||||
tidal/tidalsearchmodel.cpp
|
tidal/tidalsearchmodel.cpp
|
||||||
tidal/tidalsearchsortmodel.cpp
|
tidal/tidalsearchsortmodel.cpp
|
||||||
tidal/tidalsearchitemdelegate.cpp
|
tidal/tidalsearchitemdelegate.cpp
|
||||||
|
tidal/tidalurlhandler.cpp
|
||||||
lyrics/lyricsproviders.cpp
|
|
||||||
lyrics/lyricsprovider.cpp
|
|
||||||
lyrics/lyricsfetcher.cpp
|
|
||||||
lyrics/lyricsfetchersearch.cpp
|
|
||||||
lyrics/auddlyricsprovider.cpp
|
|
||||||
lyrics/apiseedslyricsprovider.cpp
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -369,7 +359,13 @@ set(HEADERS
|
|||||||
covermanager/coverfromurldialog.h
|
covermanager/coverfromurldialog.h
|
||||||
covermanager/musicbrainzcoverprovider.h
|
covermanager/musicbrainzcoverprovider.h
|
||||||
covermanager/discogscoverprovider.h
|
covermanager/discogscoverprovider.h
|
||||||
#covermanager/amazoncoverprovider.h
|
|
||||||
|
lyrics/lyricsproviders.h
|
||||||
|
lyrics/lyricsprovider.h
|
||||||
|
lyrics/lyricsfetcher.h
|
||||||
|
lyrics/lyricsfetchersearch.h
|
||||||
|
lyrics/auddlyricsprovider.h
|
||||||
|
lyrics/apiseedslyricsprovider.h
|
||||||
|
|
||||||
settings/settingsdialog.h
|
settings/settingsdialog.h
|
||||||
settings/settingspage.h
|
settings/settingspage.h
|
||||||
@@ -421,16 +417,6 @@ set(HEADERS
|
|||||||
globalshortcuts/globalshortcuts.h
|
globalshortcuts/globalshortcuts.h
|
||||||
globalshortcuts/gnomeglobalshortcutbackend.h
|
globalshortcuts/gnomeglobalshortcutbackend.h
|
||||||
globalshortcuts/globalshortcutgrabber.h
|
globalshortcuts/globalshortcutgrabber.h
|
||||||
|
|
||||||
device/connecteddevice.h
|
|
||||||
device/devicedatabasebackend.h
|
|
||||||
device/devicelister.h
|
|
||||||
device/devicemanager.h
|
|
||||||
device/deviceproperties.h
|
|
||||||
device/devicestatefiltermodel.h
|
|
||||||
device/deviceviewcontainer.h
|
|
||||||
device/deviceview.h
|
|
||||||
device/filesystemdevice.h
|
|
||||||
|
|
||||||
internet/internetmodel.h
|
internet/internetmodel.h
|
||||||
internet/internetservice.h
|
internet/internetservice.h
|
||||||
@@ -441,13 +427,7 @@ set(HEADERS
|
|||||||
tidal/tidalsearch.h
|
tidal/tidalsearch.h
|
||||||
tidal/tidalsearchview.h
|
tidal/tidalsearchview.h
|
||||||
tidal/tidalsearchmodel.h
|
tidal/tidalsearchmodel.h
|
||||||
|
tidal/tidalurlhandler.h
|
||||||
lyrics/lyricsproviders.h
|
|
||||||
lyrics/lyricsprovider.h
|
|
||||||
lyrics/lyricsfetcher.h
|
|
||||||
lyrics/lyricsfetchersearch.h
|
|
||||||
lyrics/auddlyricsprovider.h
|
|
||||||
lyrics/apiseedslyricsprovider.h
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -499,9 +479,6 @@ set(UI
|
|||||||
widgets/osdpretty.ui
|
widgets/osdpretty.ui
|
||||||
widgets/fileview.ui
|
widgets/fileview.ui
|
||||||
widgets/loginstatewidget.ui
|
widgets/loginstatewidget.ui
|
||||||
|
|
||||||
device/deviceproperties.ui
|
|
||||||
device/deviceviewcontainer.ui
|
|
||||||
|
|
||||||
globalshortcuts/globalshortcutgrabber.ui
|
globalshortcuts/globalshortcutgrabber.ui
|
||||||
|
|
||||||
@@ -679,6 +656,32 @@ optional_source(HAVE_DBUS
|
|||||||
core/mpris2.h
|
core/mpris2.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
optional_source(UNIX
|
||||||
|
SOURCES
|
||||||
|
device/connecteddevice.cpp
|
||||||
|
device/devicedatabasebackend.cpp
|
||||||
|
device/devicelister.cpp
|
||||||
|
device/devicemanager.cpp
|
||||||
|
device/devicestatefiltermodel.cpp
|
||||||
|
device/filesystemdevice.cpp
|
||||||
|
device/deviceviewcontainer.cpp
|
||||||
|
device/deviceview.cpp
|
||||||
|
device/deviceproperties.cpp
|
||||||
|
HEADERS
|
||||||
|
device/connecteddevice.h
|
||||||
|
device/devicedatabasebackend.h
|
||||||
|
device/devicelister.h
|
||||||
|
device/devicemanager.h
|
||||||
|
device/devicestatefiltermodel.h
|
||||||
|
device/filesystemdevice.h
|
||||||
|
device/deviceviewcontainer.h
|
||||||
|
device/deviceview.h
|
||||||
|
device/deviceproperties.h
|
||||||
|
UI
|
||||||
|
device/deviceproperties.ui
|
||||||
|
device/deviceviewcontainer.ui
|
||||||
|
)
|
||||||
|
|
||||||
if(HAVE_DBUS)
|
if(HAVE_DBUS)
|
||||||
optional_source(HAVE_DEVICEKIT
|
optional_source(HAVE_DEVICEKIT
|
||||||
SOURCES device/devicekitlister.cpp
|
SOURCES device/devicekitlister.cpp
|
||||||
|
|||||||
@@ -68,8 +68,10 @@
|
|||||||
#include "collectionitem.h"
|
#include "collectionitem.h"
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
#include "collectionview.h"
|
#include "collectionview.h"
|
||||||
#include "device/devicemanager.h"
|
#ifndef Q_OS_WIN
|
||||||
#include "device/devicestatefiltermodel.h"
|
# include "device/devicemanager.h"
|
||||||
|
# include "device/devicestatefiltermodel.h"
|
||||||
|
#endif
|
||||||
#include "dialogs/edittagdialog.h"
|
#include "dialogs/edittagdialog.h"
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
#include "dialogs/organisedialog.h"
|
#include "dialogs/organisedialog.h"
|
||||||
@@ -460,7 +462,9 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||||
|
#endif
|
||||||
//delete_ = context_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(Delete()));
|
//delete_ = context_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(Delete()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -477,7 +481,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
context_menu_->addMenu(filter_->menu());
|
context_menu_->addMenu(filter_->menu());
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||||
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
||||||
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), copy_to_device_, SLOT(setDisabled(bool)));
|
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), copy_to_device_, SLOT(setDisabled(bool)));
|
||||||
#endif
|
#endif
|
||||||
@@ -518,7 +522,9 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
// only when no smart playlists selected
|
// only when no smart playlists selected
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
organise_->setVisible(regular_elements_only);
|
organise_->setVisible(regular_elements_only);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_->setVisible(regular_elements_only);
|
copy_to_device_->setVisible(regular_elements_only);
|
||||||
|
#endif
|
||||||
//delete_->setVisible(regular_elements_only);
|
//delete_->setVisible(regular_elements_only);
|
||||||
#endif
|
#endif
|
||||||
show_in_various_->setVisible(regular_elements_only);
|
show_in_various_->setVisible(regular_elements_only);
|
||||||
@@ -527,7 +533,9 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
// only when all selected items are editable
|
// only when all selected items are editable
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
organise_->setEnabled(regular_elements == regular_editable);
|
organise_->setEnabled(regular_elements == regular_editable);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
||||||
|
#endif
|
||||||
//delete_->setEnabled(regular_elements == regular_editable);
|
//delete_->setEnabled(regular_elements == regular_editable);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -670,7 +678,7 @@ void CollectionView::EditTracks() {
|
|||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
void CollectionView::CopyToDevice() {
|
void CollectionView::CopyToDevice() {
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
if (!organise_dialog_)
|
if (!organise_dialog_)
|
||||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
||||||
|
|
||||||
@@ -678,7 +686,7 @@ void CollectionView::CopyToDevice() {
|
|||||||
organise_dialog_->SetCopy(true);
|
organise_dialog_->SetCopy(true);
|
||||||
organise_dialog_->SetSongs(GetSelectedSongs());
|
organise_dialog_->SetSongs(GetSelectedSongs());
|
||||||
organise_dialog_->show();
|
organise_dialog_->show();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ signals:
|
|||||||
QAction *open_in_new_playlist_;
|
QAction *open_in_new_playlist_;
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
QAction *organise_;
|
QAction *organise_;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
QAction *copy_to_device_;
|
QAction *copy_to_device_;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
QAction *delete_;
|
QAction *delete_;
|
||||||
QAction *edit_track_;
|
QAction *edit_track_;
|
||||||
|
|||||||
@@ -66,9 +66,12 @@
|
|||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
#include "collection/collectionbackend.h"
|
#include "collection/collectionbackend.h"
|
||||||
#include "collection/collectiondirectorymodel.h"
|
#include "collection/collectiondirectorymodel.h"
|
||||||
|
#include "collection/collectionmodel.h"
|
||||||
#include "collection/collectionitem.h"
|
#include "collection/collectionitem.h"
|
||||||
#include "device/devicemanager.h"
|
#ifndef Q_OS_WIN
|
||||||
#include "device/devicestatefiltermodel.h"
|
# include "device/devicemanager.h"
|
||||||
|
# include "device/devicestatefiltermodel.h"
|
||||||
|
#endif
|
||||||
#include "dialogs/edittagdialog.h"
|
#include "dialogs/edittagdialog.h"
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
#include "dialogs/organisedialog.h"
|
#include "dialogs/organisedialog.h"
|
||||||
@@ -263,9 +266,6 @@ void ContextAlbumsView::SaveFocus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ContextAlbumsView::SaveContainerPath(const QModelIndex &child) {
|
void ContextAlbumsView::SaveContainerPath(const QModelIndex &child) {
|
||||||
|
|
||||||
|
|
||||||
// return;
|
|
||||||
|
|
||||||
QModelIndex current = model()->parent(child);
|
QModelIndex current = model()->parent(child);
|
||||||
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
QVariant type = model()->data(current, ContextAlbumsModel::Role_Type);
|
||||||
@@ -359,7 +359,6 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
if (!context_menu_) {
|
if (!context_menu_) {
|
||||||
context_menu_ = new QMenu(this);
|
context_menu_ = new QMenu(this);
|
||||||
//context_menu_->setStyleSheet("background-color: #3DADE8;");
|
|
||||||
|
|
||||||
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
add_to_playlist_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Append to current playlist"), this, SLOT(AddToPlaylist()));
|
||||||
load_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(Load()));
|
load_ = context_menu_->addAction(IconLoader::Load("media-play"), tr("Replace current playlist"), this, SLOT(Load()));
|
||||||
@@ -371,7 +370,9 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
organise_ = context_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(Organise()));
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
copy_to_device_ = context_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(CopyToDevice()));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
@@ -381,7 +382,7 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||||
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
||||||
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), copy_to_device_, SLOT(setDisabled(bool)));
|
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), copy_to_device_, SLOT(setDisabled(bool)));
|
||||||
#endif
|
#endif
|
||||||
@@ -418,13 +419,17 @@ void ContextAlbumsView::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
organise_->setVisible(regular_elements_only);
|
organise_->setVisible(regular_elements_only);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_->setVisible(regular_elements_only);
|
copy_to_device_->setVisible(regular_elements_only);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// only when all selected items are editable
|
// only when all selected items are editable
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
organise_->setEnabled(regular_elements == regular_editable);
|
organise_->setEnabled(regular_elements == regular_editable);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
copy_to_device_->setEnabled(regular_elements == regular_editable);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
context_menu_->popup(e->globalPos());
|
context_menu_->popup(e->globalPos());
|
||||||
@@ -509,7 +514,7 @@ void ContextAlbumsView::EditTracks() {
|
|||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
void ContextAlbumsView::CopyToDevice() {
|
void ContextAlbumsView::CopyToDevice() {
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
if (!organise_dialog_)
|
if (!organise_dialog_)
|
||||||
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
organise_dialog_.reset(new OrganiseDialog(app_->task_manager()));
|
||||||
|
|
||||||
@@ -517,7 +522,7 @@ void ContextAlbumsView::CopyToDevice() {
|
|||||||
organise_dialog_->SetCopy(true);
|
organise_dialog_->SetCopy(true);
|
||||||
organise_dialog_->SetSongs(GetSelectedSongs());
|
organise_dialog_->SetSongs(GetSelectedSongs());
|
||||||
organise_dialog_->show();
|
organise_dialog_->show();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,9 @@ signals:
|
|||||||
void OpenInNewPlaylist();
|
void OpenInNewPlaylist();
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
void Organise();
|
void Organise();
|
||||||
|
//#ifndef Q_OS_WIN
|
||||||
void CopyToDevice();
|
void CopyToDevice();
|
||||||
|
//#endif
|
||||||
#endif
|
#endif
|
||||||
void EditTracks();
|
void EditTracks();
|
||||||
void ShowInBrowser();
|
void ShowInBrowser();
|
||||||
@@ -124,7 +126,9 @@ signals:
|
|||||||
QAction *open_in_new_playlist_;
|
QAction *open_in_new_playlist_;
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
QAction *organise_;
|
QAction *organise_;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
QAction *copy_to_device_;
|
QAction *copy_to_device_;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
QAction *delete_;
|
QAction *delete_;
|
||||||
QAction *edit_track_;
|
QAction *edit_track_;
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ ContextView::ContextView(QWidget *parent) :
|
|||||||
timeline_fade_(new QTimeLine(1000, this)),
|
timeline_fade_(new QTimeLine(1000, this)),
|
||||||
image_strawberry_(":/pictures/strawberry.png"),
|
image_strawberry_(":/pictures/strawberry.png"),
|
||||||
active_(false),
|
active_(false),
|
||||||
downloading_covers_(false)
|
downloading_covers_(false),
|
||||||
|
lyrics_id_(-1)
|
||||||
{
|
{
|
||||||
|
|
||||||
ui_->setupUi(this);
|
ui_->setupUi(this);
|
||||||
@@ -173,10 +174,10 @@ void ContextView::Playing() {}
|
|||||||
void ContextView::Stopped() {
|
void ContextView::Stopped() {
|
||||||
|
|
||||||
active_ = false;
|
active_ = false;
|
||||||
song_playing_ = song_empty_;
|
song_playing_ = Song();
|
||||||
song_ = song_empty_;
|
song_ = Song();
|
||||||
downloading_covers_ = false;
|
downloading_covers_ = false;
|
||||||
prev_artist_ = QString();
|
song_prev_ = Song();
|
||||||
lyrics_ = QString();
|
lyrics_ = QString();
|
||||||
SetImage(image_strawberry_);
|
SetImage(image_strawberry_);
|
||||||
|
|
||||||
@@ -190,21 +191,40 @@ void ContextView::UpdateNoSong() {
|
|||||||
|
|
||||||
void ContextView::SongChanged(const Song &song) {
|
void ContextView::SongChanged(const Song &song) {
|
||||||
|
|
||||||
image_previous_ = image_original_;
|
if (song_playing_.is_valid() && song.id() == song_playing_.id() && song.url() == song_playing_.url()) {
|
||||||
prev_artist_ = song_playing_.artist();
|
UpdateSong(song);
|
||||||
lyrics_ = song.lyrics();
|
}
|
||||||
song_playing_ = song;
|
else {
|
||||||
song_ = song;
|
song_prev_ = song_playing_;
|
||||||
UpdateSong();
|
lyrics_ = song.lyrics();
|
||||||
update();
|
lyrics_id_ = -1;
|
||||||
if (action_show_lyrics_->isChecked()) lyrics_fetcher_->Search(song.artist(), song.album(), song.title());
|
song_playing_ = song;
|
||||||
|
song_ = song;
|
||||||
|
SetSong(song);
|
||||||
|
if (lyrics_.isEmpty() && action_show_lyrics_->isChecked()) {
|
||||||
|
lyrics_fetcher_->Clear();
|
||||||
|
lyrics_id_ = lyrics_fetcher_->Search(song.artist(), song.album(), song.title());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::SetText(QLabel *label, int value, const QString &suffix, const QString &def) {
|
void ContextView::SetLabelEnabled(QLabel *label) {
|
||||||
|
label->setEnabled(true);
|
||||||
|
label->setVisible(true);
|
||||||
|
label->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextView::SetLabelText(QLabel *label, int value, const QString &suffix, const QString &def) {
|
||||||
label->setText(value <= 0 ? def : (QString::number(value) + " " + suffix));
|
label->setText(value <= 0 ? def : (QString::number(value) + " " + suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextView::SetLabelDisabled(QLabel *label) {
|
||||||
|
label->setEnabled(false);
|
||||||
|
label->setVisible(false);
|
||||||
|
label->setMaximumSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void ContextView::NoSong() {
|
void ContextView::NoSong() {
|
||||||
|
|
||||||
ui_->label_stop_top->setStyleSheet(
|
ui_->label_stop_top->setStyleSheet(
|
||||||
@@ -232,7 +252,7 @@ void ContextView::NoSong() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::UpdateSong() {
|
void ContextView::SetSong(const Song &song) {
|
||||||
|
|
||||||
QList <QLabel *> labels_play_data;
|
QList <QLabel *> labels_play_data;
|
||||||
|
|
||||||
@@ -251,85 +271,58 @@ void ContextView::UpdateSong() {
|
|||||||
"font: 11pt;"
|
"font: 11pt;"
|
||||||
"font-weight: regular;"
|
"font-weight: regular;"
|
||||||
);
|
);
|
||||||
ui_->label_play_top->setText( QString("<b>%1 - %2</b><br/>%3").arg(song_.PrettyTitle().toHtmlEscaped(), song_.artist().toHtmlEscaped(), song_.album().toHtmlEscaped()));
|
ui_->label_play_top->setText( QString("<b>%1 - %2</b><br/>%3").arg(song.PrettyTitle().toHtmlEscaped(), song.artist().toHtmlEscaped(), song.album().toHtmlEscaped()));
|
||||||
|
|
||||||
if (action_show_data_->isChecked()) {
|
if (action_show_data_->isChecked()) {
|
||||||
for (QLabel *l : labels_play_data) {
|
|
||||||
l->setEnabled(true);
|
|
||||||
l->setVisible(true);
|
|
||||||
l->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
||||||
}
|
|
||||||
ui_->layout_play_data->setEnabled(true);
|
ui_->layout_play_data->setEnabled(true);
|
||||||
ui_->filetype->setText(song_.TextForFiletype());
|
SetLabelEnabled(ui_->label_filetype);
|
||||||
ui_->length->setText(Utilities::PrettyTimeNanosec(song_.length_nanosec()));
|
SetLabelEnabled(ui_->filetype);
|
||||||
if (song_.samplerate() <= 0) {
|
SetLabelEnabled(ui_->label_length);
|
||||||
ui_->label_samplerate->setEnabled(false);
|
SetLabelEnabled(ui_->length);
|
||||||
ui_->label_samplerate->setVisible(false);
|
ui_->filetype->setText(song.TextForFiletype());
|
||||||
ui_->label_samplerate->setMaximumSize(0, 0);
|
ui_->length->setText(Utilities::PrettyTimeNanosec(song.length_nanosec()));
|
||||||
ui_->samplerate->setEnabled(false);
|
if (song.samplerate() <= 0) {
|
||||||
ui_->samplerate->setVisible(false);
|
SetLabelDisabled(ui_->label_samplerate);
|
||||||
ui_->samplerate->setMaximumSize(0, 0);
|
SetLabelDisabled(ui_->samplerate);
|
||||||
ui_->samplerate->clear();
|
ui_->samplerate->clear();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->label_samplerate->setEnabled(true);
|
SetLabelEnabled(ui_->label_samplerate);
|
||||||
ui_->label_samplerate->setVisible(true);
|
SetLabelEnabled(ui_->samplerate);
|
||||||
ui_->label_samplerate->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
SetLabelText(ui_->samplerate, song.samplerate(), "Hz");
|
||||||
ui_->samplerate->setEnabled(true);
|
|
||||||
ui_->samplerate->setVisible(true);
|
|
||||||
ui_->samplerate->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
||||||
SetText(ui_->samplerate, song_.samplerate(), "Hz");
|
|
||||||
}
|
}
|
||||||
if (song_.bitdepth() <= 0) {
|
if (song.bitdepth() <= 0) {
|
||||||
ui_->label_bitdepth->setEnabled(false);
|
SetLabelDisabled(ui_->label_bitdepth);
|
||||||
ui_->label_bitdepth->setVisible(false);
|
SetLabelDisabled(ui_->bitdepth);
|
||||||
ui_->label_bitdepth->setMaximumSize(0, 0);
|
|
||||||
ui_->bitdepth->setEnabled(false);
|
|
||||||
ui_->bitdepth->setVisible(false);
|
|
||||||
ui_->bitdepth->setMaximumSize(0, 0);
|
|
||||||
ui_->bitdepth->clear();
|
ui_->bitdepth->clear();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->label_bitdepth->setEnabled(true);
|
SetLabelEnabled(ui_->label_bitdepth);
|
||||||
ui_->label_bitdepth->setVisible(true);
|
SetLabelEnabled(ui_->bitdepth);
|
||||||
ui_->label_bitdepth->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
SetLabelText(ui_->bitdepth, song.bitdepth(), "Bit");
|
||||||
ui_->bitdepth->setEnabled(true);
|
|
||||||
ui_->bitdepth->setVisible(true);
|
|
||||||
ui_->bitdepth->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
||||||
SetText(ui_->bitdepth, song_.bitdepth(), "Bit");
|
|
||||||
}
|
}
|
||||||
if (song_.bitrate() <= 0) {
|
if (song.bitrate() <= 0) {
|
||||||
ui_->label_bitrate->setEnabled(false);
|
SetLabelDisabled(ui_->label_bitrate);
|
||||||
ui_->label_bitrate->setVisible(false);
|
SetLabelDisabled(ui_->bitrate);
|
||||||
ui_->label_bitrate->setMaximumSize(0, 0);
|
|
||||||
ui_->bitrate->setEnabled(false);
|
|
||||||
ui_->bitrate->setVisible(false);
|
|
||||||
ui_->bitrate->setMaximumSize(0, 0);
|
|
||||||
ui_->bitrate->clear();
|
ui_->bitrate->clear();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->label_bitrate->setEnabled(true);
|
SetLabelEnabled(ui_->label_bitrate);
|
||||||
ui_->label_bitrate->setVisible(true);
|
SetLabelEnabled(ui_->bitrate);
|
||||||
ui_->label_bitrate->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
SetLabelText(ui_->bitrate, song.bitrate(), tr("kbps"));
|
||||||
ui_->bitrate->setEnabled(true);
|
|
||||||
ui_->bitrate->setVisible(true);
|
|
||||||
ui_->bitrate->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
||||||
SetText(ui_->bitrate, song_.bitrate(), tr("kbps"));
|
|
||||||
}
|
}
|
||||||
ui_->spacer_play_data->changeSize(20, 20, QSizePolicy::Fixed);
|
ui_->spacer_play_data->changeSize(20, 20, QSizePolicy::Fixed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (QLabel *l : labels_play_data) {
|
|
||||||
l->setEnabled(false);
|
|
||||||
l->setVisible(false);
|
|
||||||
l->setMaximumSize(0, 0);
|
|
||||||
}
|
|
||||||
ui_->layout_play_data->setEnabled(false);
|
|
||||||
ui_->filetype->clear();
|
ui_->filetype->clear();
|
||||||
ui_->length->clear();
|
ui_->length->clear();
|
||||||
ui_->samplerate->clear();
|
ui_->samplerate->clear();
|
||||||
ui_->bitdepth->clear();
|
ui_->bitdepth->clear();
|
||||||
ui_->bitrate->clear();
|
ui_->bitrate->clear();
|
||||||
|
for (QLabel *l : labels_play_data) {
|
||||||
|
SetLabelDisabled(l);
|
||||||
|
}
|
||||||
|
ui_->layout_play_data->setEnabled(false);
|
||||||
ui_->spacer_play_data->changeSize(0, 0, QSizePolicy::Fixed);
|
ui_->spacer_play_data->changeSize(0, 0, QSizePolicy::Fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,18 +396,18 @@ void ContextView::UpdateSong() {
|
|||||||
ui_->device->setMaximumSize(0, 0);
|
ui_->device->setMaximumSize(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action_show_albums_->isChecked() && prev_artist_ != song_.artist()) {
|
if (action_show_albums_->isChecked() && song_prev_.artist() != song.artist()) {
|
||||||
const QueryOptions opt;
|
const QueryOptions opt;
|
||||||
CollectionBackend::AlbumList albumlist;
|
CollectionBackend::AlbumList albumlist;
|
||||||
ui_->widget_play_albums->albums_model()->Reset();
|
ui_->widget_play_albums->albums_model()->Reset();
|
||||||
albumlist = app_->collection_backend()->GetAlbumsByArtist(song_.artist(), opt);
|
albumlist = app_->collection_backend()->GetAlbumsByArtist(song.artist(), opt);
|
||||||
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(QString("<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);
|
||||||
ui_->widget_play_albums->albums_model()->AddSongs(songs);
|
ui_->widget_play_albums->albums_model()->AddSongs(songs);
|
||||||
}
|
}
|
||||||
ui_->widget_play_albums->setEnabled(true);
|
ui_->widget_play_albums->setEnabled(true);
|
||||||
@@ -454,9 +447,62 @@ void ContextView::UpdateSong() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextView::UpdateSong(const Song &song) {
|
||||||
|
|
||||||
|
if (song.artist() != song_playing_.artist() || song.album() != song_playing_.album() || song.title() != song_playing_.title()) {
|
||||||
|
ui_->label_play_top->setText( QString("<b>%1 - %2</b><br/>%3").arg(song.PrettyTitle().toHtmlEscaped(), song.artist().toHtmlEscaped(), song.album().toHtmlEscaped()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action_show_data_->isChecked()) {
|
||||||
|
if (song.filetype() != song_playing_.filetype()) ui_->filetype->setText(song.TextForFiletype());
|
||||||
|
if (song.length_nanosec() != song_playing_.length_nanosec()) ui_->label_length->setText(Utilities::PrettyTimeNanosec(song.length_nanosec()));
|
||||||
|
if (song.samplerate() != song_playing_.samplerate()) {
|
||||||
|
if (song.samplerate() <= 0) {
|
||||||
|
SetLabelDisabled(ui_->label_samplerate);
|
||||||
|
SetLabelDisabled(ui_->samplerate);
|
||||||
|
ui_->samplerate->clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetLabelEnabled(ui_->label_samplerate);
|
||||||
|
SetLabelEnabled(ui_->samplerate);
|
||||||
|
SetLabelText(ui_->samplerate, song.samplerate(), "Hz");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (song.bitdepth() != song_playing_.bitdepth()) {
|
||||||
|
if (song.bitdepth() <= 0) {
|
||||||
|
SetLabelDisabled(ui_->label_bitdepth);
|
||||||
|
SetLabelDisabled(ui_->bitdepth);
|
||||||
|
ui_->bitdepth->clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetLabelEnabled(ui_->label_bitdepth);
|
||||||
|
SetLabelEnabled(ui_->bitdepth);
|
||||||
|
SetLabelText(ui_->bitdepth, song.bitdepth(), "Bit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (song.bitrate() != song_playing_.bitrate()) {
|
||||||
|
if (song.bitrate() <= 0) {
|
||||||
|
SetLabelDisabled(ui_->label_bitrate);
|
||||||
|
SetLabelDisabled(ui_->bitrate);
|
||||||
|
ui_->bitrate->clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetLabelEnabled(ui_->label_bitrate);
|
||||||
|
SetLabelEnabled(ui_->bitrate);
|
||||||
|
SetLabelText(ui_->bitrate, song.bitrate(), tr("kbps"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
song_playing_ = song;
|
||||||
|
song_ = song;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ContextView::UpdateLyrics(quint64 id, const QString lyrics) {
|
void ContextView::UpdateLyrics(quint64 id, const QString lyrics) {
|
||||||
|
|
||||||
|
if (id != lyrics_id_) return;
|
||||||
lyrics_ = lyrics;
|
lyrics_ = lyrics;
|
||||||
|
lyrics_id_ = -1;
|
||||||
if (action_show_lyrics_->isChecked()) {
|
if (action_show_lyrics_->isChecked()) {
|
||||||
ui_->label_play_lyrics->setText(lyrics);
|
ui_->label_play_lyrics->setText(lyrics);
|
||||||
}
|
}
|
||||||
@@ -551,7 +597,9 @@ void ContextView::ScaleCover() {
|
|||||||
|
|
||||||
void ContextView::AlbumArtLoaded(const Song &song, const QString&, const QImage &image) {
|
void ContextView::AlbumArtLoaded(const Song &song, const QString&, const QImage &image) {
|
||||||
|
|
||||||
|
if (song.id() != song_playing_.id() || song.url() != song_playing_.url()) return;
|
||||||
if (song.effective_albumartist() != song_playing_.effective_albumartist() || song.effective_album() != song_playing_.effective_album() || song.title() != song_playing_.title()) return;
|
if (song.effective_albumartist() != song_playing_.effective_albumartist() || song.effective_album() != song_playing_.effective_album() || song.title() != song_playing_.title()) return;
|
||||||
|
if (image == image_original_) return;
|
||||||
|
|
||||||
active_ = true;
|
active_ = true;
|
||||||
downloading_covers_ = false;
|
downloading_covers_ = false;
|
||||||
@@ -572,6 +620,7 @@ void ContextView::SetImage(const QImage &image) {
|
|||||||
DrawImage(&p);
|
DrawImage(&p);
|
||||||
p.end();
|
p.end();
|
||||||
|
|
||||||
|
image_previous_ = image_original_;
|
||||||
image_original_ = image;
|
image_original_ = image;
|
||||||
|
|
||||||
ScaleCover();
|
ScaleCover();
|
||||||
@@ -623,7 +672,7 @@ void ContextView::ActionShowData() {
|
|||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("show_data", action_show_data_->isChecked());
|
s.setValue("show_data", action_show_data_->isChecked());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
UpdateSong();
|
SetSong(song_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ActionShowOutput() {
|
void ContextView::ActionShowOutput() {
|
||||||
@@ -631,7 +680,7 @@ void ContextView::ActionShowOutput() {
|
|||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("show_output", action_show_output_->isChecked());
|
s.setValue("show_output", action_show_output_->isChecked());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
UpdateSong();
|
SetSong(song_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ActionShowAlbums() {
|
void ContextView::ActionShowAlbums() {
|
||||||
@@ -639,8 +688,8 @@ void ContextView::ActionShowAlbums() {
|
|||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("show_albums", action_show_albums_->isChecked());
|
s.setValue("show_albums", action_show_albums_->isChecked());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
prev_artist_ = QString();
|
song_prev_ = Song();
|
||||||
UpdateSong();
|
SetSong(song_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::ActionShowLyrics() {
|
void ContextView::ActionShowLyrics() {
|
||||||
@@ -648,8 +697,11 @@ void ContextView::ActionShowLyrics() {
|
|||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("show_lyrics", action_show_lyrics_->isChecked());
|
s.setValue("show_lyrics", action_show_lyrics_->isChecked());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
UpdateSong();
|
SetSong(song_);
|
||||||
if (lyrics_.isEmpty() && action_show_lyrics_->isChecked()) lyrics_fetcher_->Search(song_.artist(), song_.album(), song_.title());
|
if (lyrics_.isEmpty() && action_show_lyrics_->isChecked()) {
|
||||||
|
lyrics_fetcher_->Clear();
|
||||||
|
lyrics_id_ = lyrics_fetcher_->Search(song_.artist(), song_.album(), song_.title());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextView::SearchCoverAutomatically() {
|
void ContextView::SearchCoverAutomatically() {
|
||||||
|
|||||||
@@ -94,21 +94,23 @@ class ContextView : public QWidget {
|
|||||||
AlbumCoverLoaderOptions cover_loader_options_;
|
AlbumCoverLoaderOptions cover_loader_options_;
|
||||||
Song song_;
|
Song song_;
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
Song song_empty_;
|
Song song_prev_;
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
QImage image_previous_;
|
QImage image_previous_;
|
||||||
QPixmap pixmap_current_;
|
QPixmap pixmap_current_;
|
||||||
QPixmap pixmap_previous_;
|
QPixmap pixmap_previous_;
|
||||||
qreal pixmap_previous_opacity_;
|
qreal pixmap_previous_opacity_;
|
||||||
std::unique_ptr<QMovie> spinner_animation_;
|
std::unique_ptr<QMovie> spinner_animation_;
|
||||||
|
qint64 lyrics_id_;
|
||||||
QString prev_artist_;
|
|
||||||
QString lyrics_;
|
QString lyrics_;
|
||||||
|
|
||||||
void AddActions();
|
void AddActions();
|
||||||
void SetText(QLabel *label, int value, const QString &suffix, const QString &def = QString());
|
void SetLabelEnabled(QLabel *label);
|
||||||
|
void SetLabelDisabled(QLabel *label);
|
||||||
|
void SetLabelText(QLabel *label, int value, const QString &suffix, const QString &def = QString());
|
||||||
void NoSong();
|
void NoSong();
|
||||||
void UpdateSong();
|
void SetSong(const Song &song);
|
||||||
|
void UpdateSong(const Song &song);
|
||||||
void SetImage(const QImage &image);
|
void SetImage(const QImage &image);
|
||||||
void DrawImage(QPainter *p);
|
void DrawImage(QPainter *p);
|
||||||
void ScaleCover();
|
void ScaleCover();
|
||||||
|
|||||||
@@ -38,7 +38,9 @@
|
|||||||
#include "appearance.h"
|
#include "appearance.h"
|
||||||
|
|
||||||
#include "engine/enginedevice.h"
|
#include "engine/enginedevice.h"
|
||||||
#include "device/devicemanager.h"
|
#ifndef Q_OS_WIN
|
||||||
|
# include "device/devicemanager.h"
|
||||||
|
#endif
|
||||||
#include "collection/collection.h"
|
#include "collection/collection.h"
|
||||||
#include "playlist/playlistbackend.h"
|
#include "playlist/playlistbackend.h"
|
||||||
#include "playlist/playlistmanager.h"
|
#include "playlist/playlistmanager.h"
|
||||||
@@ -48,7 +50,6 @@
|
|||||||
#ifdef HAVE_LIBLASTFM
|
#ifdef HAVE_LIBLASTFM
|
||||||
#include "covermanager/lastfmcoverprovider.h"
|
#include "covermanager/lastfmcoverprovider.h"
|
||||||
#endif
|
#endif
|
||||||
//#include "covermanager/amazoncoverprovider.h"
|
|
||||||
#include "covermanager/discogscoverprovider.h"
|
#include "covermanager/discogscoverprovider.h"
|
||||||
#include "covermanager/musicbrainzcoverprovider.h"
|
#include "covermanager/musicbrainzcoverprovider.h"
|
||||||
|
|
||||||
@@ -81,7 +82,9 @@ class ApplicationImpl {
|
|||||||
task_manager_([=]() { return new TaskManager(app); }),
|
task_manager_([=]() { return new TaskManager(app); }),
|
||||||
player_([=]() { return new Player(app, app); }),
|
player_([=]() { return new Player(app, app); }),
|
||||||
enginedevice_([=]() { return new EngineDevice(app); }),
|
enginedevice_([=]() { return new EngineDevice(app); }),
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
device_manager_([=]() { return new DeviceManager(app, app); }),
|
device_manager_([=]() { return new DeviceManager(app, app); }),
|
||||||
|
#endif
|
||||||
collection_([=]() { return new SCollection(app, app); }),
|
collection_([=]() { return new SCollection(app, app); }),
|
||||||
playlist_backend_([=]() {
|
playlist_backend_([=]() {
|
||||||
PlaylistBackend *backend = new PlaylistBackend(app, app);
|
PlaylistBackend *backend = new PlaylistBackend(app, app);
|
||||||
@@ -95,7 +98,6 @@ class ApplicationImpl {
|
|||||||
#ifdef HAVE_LIBLASTFM
|
#ifdef HAVE_LIBLASTFM
|
||||||
cover_providers->AddProvider(new LastFmCoverProvider(app));
|
cover_providers->AddProvider(new LastFmCoverProvider(app));
|
||||||
#endif
|
#endif
|
||||||
//cover_providers->AddProvider(new AmazonCoverProvider(app));
|
|
||||||
cover_providers->AddProvider(new DiscogsCoverProvider(app));
|
cover_providers->AddProvider(new DiscogsCoverProvider(app));
|
||||||
cover_providers->AddProvider(new MusicbrainzCoverProvider(app));
|
cover_providers->AddProvider(new MusicbrainzCoverProvider(app));
|
||||||
return cover_providers;
|
return cover_providers;
|
||||||
@@ -122,7 +124,9 @@ class ApplicationImpl {
|
|||||||
Lazy<TaskManager> task_manager_;
|
Lazy<TaskManager> task_manager_;
|
||||||
Lazy<Player> player_;
|
Lazy<Player> player_;
|
||||||
Lazy<EngineDevice> enginedevice_;
|
Lazy<EngineDevice> enginedevice_;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
Lazy<DeviceManager> device_manager_;
|
Lazy<DeviceManager> device_manager_;
|
||||||
|
#endif
|
||||||
Lazy<SCollection> collection_;
|
Lazy<SCollection> collection_;
|
||||||
Lazy<PlaylistBackend> playlist_backend_;
|
Lazy<PlaylistBackend> playlist_backend_;
|
||||||
Lazy<PlaylistManager> playlist_manager_;
|
Lazy<PlaylistManager> playlist_manager_;
|
||||||
@@ -148,7 +152,9 @@ Application::~Application() {
|
|||||||
|
|
||||||
// It's important that the device manager is deleted before the database.
|
// It's important that the device manager is deleted before the database.
|
||||||
// Deleting the database deletes all objects that have been created in its thread, including some device collection backends.
|
// Deleting the database deletes all objects that have been created in its thread, including some device collection backends.
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
p_->device_manager_.reset();
|
p_->device_manager_.reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
for (QThread *thread : threads_) {
|
for (QThread *thread : threads_) {
|
||||||
thread->quit();
|
thread->quit();
|
||||||
@@ -198,9 +204,11 @@ CurrentArtLoader *Application::current_art_loader() const {
|
|||||||
|
|
||||||
Database *Application::database() const { return p_->database_.get(); }
|
Database *Application::database() const { return p_->database_.get(); }
|
||||||
|
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
DeviceManager *Application::device_manager() const {
|
DeviceManager *Application::device_manager() const {
|
||||||
return p_->device_manager_.get();
|
return p_->device_manager_.get();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SCollection *Application::collection() const { return p_->collection_.get(); }
|
SCollection *Application::collection() const { return p_->collection_.get(); }
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ class CollectionBackend;
|
|||||||
class CollectionModel;
|
class CollectionModel;
|
||||||
class PlaylistBackend;
|
class PlaylistBackend;
|
||||||
class PlaylistManager;
|
class PlaylistManager;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
class DeviceManager;
|
class DeviceManager;
|
||||||
|
#endif
|
||||||
class CoverProviders;
|
class CoverProviders;
|
||||||
class AlbumCoverLoader;
|
class AlbumCoverLoader;
|
||||||
class CurrentArtLoader;
|
class CurrentArtLoader;
|
||||||
@@ -68,7 +70,9 @@ class Application : public QObject {
|
|||||||
TaskManager *task_manager() const;
|
TaskManager *task_manager() const;
|
||||||
Player *player() const;
|
Player *player() const;
|
||||||
EngineDevice *enginedevice() const;
|
EngineDevice *enginedevice() const;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
DeviceManager *device_manager() const;
|
DeviceManager *device_manager() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
SCollection *collection() const;
|
SCollection *collection() 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, Jonas Kvinge <jonas@strawbs.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
|
||||||
@@ -121,10 +121,12 @@
|
|||||||
#include "covermanager/albumcoverchoicecontroller.h"
|
#include "covermanager/albumcoverchoicecontroller.h"
|
||||||
#include "covermanager/albumcoverloader.h"
|
#include "covermanager/albumcoverloader.h"
|
||||||
#include "covermanager/currentartloader.h"
|
#include "covermanager/currentartloader.h"
|
||||||
#include "device/devicemanager.h"
|
#ifndef Q_OS_WIN
|
||||||
#include "device/devicestatefiltermodel.h"
|
# include "device/devicemanager.h"
|
||||||
#include "device/deviceview.h"
|
# include "device/devicestatefiltermodel.h"
|
||||||
#include "device/deviceviewcontainer.h"
|
# include "device/deviceview.h"
|
||||||
|
# include "device/deviceviewcontainer.h"
|
||||||
|
#endif
|
||||||
#include "transcoder/transcodedialog.h"
|
#include "transcoder/transcodedialog.h"
|
||||||
#include "settings/behavioursettingspage.h"
|
#include "settings/behavioursettingspage.h"
|
||||||
#include "settings/playbacksettingspage.h"
|
#include "settings/playbacksettingspage.h"
|
||||||
@@ -167,8 +169,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
context_view_(new ContextView(this)),
|
context_view_(new ContextView(this)),
|
||||||
collection_view_(new CollectionViewContainer(this)),
|
collection_view_(new CollectionViewContainer(this)),
|
||||||
file_view_(new FileView(this)),
|
file_view_(new FileView(this)),
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
device_view_container_(new DeviceViewContainer(this)),
|
device_view_container_(new DeviceViewContainer(this)),
|
||||||
device_view_(device_view_container_->view()),
|
device_view_(device_view_container_->view()),
|
||||||
|
#endif
|
||||||
playlist_list_(new PlaylistListContainer(this)),
|
playlist_list_(new PlaylistListContainer(this)),
|
||||||
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
|
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
|
||||||
cover_manager_([=]() {
|
cover_manager_([=]() {
|
||||||
@@ -246,7 +250,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
|
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
|
||||||
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
|
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
|
||||||
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices"));
|
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices"));
|
||||||
|
#endif
|
||||||
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal", "Tidal"));
|
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal", "Tidal"));
|
||||||
//ui_->tabs->AddSpacer();
|
//ui_->tabs->AddSpacer();
|
||||||
|
|
||||||
@@ -284,7 +290,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
|
|
||||||
collection_view_->view()->setModel(collection_sort_model_);
|
collection_view_->view()->setModel(collection_sort_model_);
|
||||||
collection_view_->view()->SetApplication(app_);
|
collection_view_->view()->SetApplication(app_);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
device_view_->SetApplication(app_);
|
device_view_->SetApplication(app_);
|
||||||
|
#endif
|
||||||
playlist_list_->SetApplication(app_);
|
playlist_list_->SetApplication(app_);
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
@@ -344,7 +352,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
connect(file_view_, SIGNAL(CopyToCollection(QList<QUrl>)), SLOT(CopyFilesToCollection(QList<QUrl>)));
|
connect(file_view_, SIGNAL(CopyToCollection(QList<QUrl>)), SLOT(CopyFilesToCollection(QList<QUrl>)));
|
||||||
connect(file_view_, SIGNAL(MoveToCollection(QList<QUrl>)), SLOT(MoveFilesToCollection(QList<QUrl>)));
|
connect(file_view_, SIGNAL(MoveToCollection(QList<QUrl>)), SLOT(MoveFilesToCollection(QList<QUrl>)));
|
||||||
connect(file_view_, SIGNAL(EditTags(QList<QUrl>)), SLOT(EditFileTags(QList<QUrl>)));
|
connect(file_view_, SIGNAL(EditTags(QList<QUrl>)), SLOT(EditFileTags(QList<QUrl>)));
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
connect(file_view_, SIGNAL(CopyToDevice(QList<QUrl>)), SLOT(CopyFilesToDevice(QList<QUrl>)));
|
connect(file_view_, SIGNAL(CopyToDevice(QList<QUrl>)), SLOT(CopyFilesToDevice(QList<QUrl>)));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
file_view_->SetTaskManager(app_->task_manager());
|
file_view_->SetTaskManager(app_->task_manager());
|
||||||
|
|
||||||
@@ -469,8 +479,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
connect(app_->task_manager(), SIGNAL(PauseCollectionWatchers()), app_->collection(), SLOT(PauseWatcher()));
|
connect(app_->task_manager(), SIGNAL(PauseCollectionWatchers()), app_->collection(), SLOT(PauseWatcher()));
|
||||||
connect(app_->task_manager(), SIGNAL(ResumeCollectionWatchers()), app_->collection(), SLOT(ResumeWatcher()));
|
connect(app_->task_manager(), SIGNAL(ResumeCollectionWatchers()), app_->collection(), SLOT(ResumeWatcher()));
|
||||||
|
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
// Devices connections
|
// Devices connections
|
||||||
connect(device_view_, SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
connect(device_view_, SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Collection filter widget
|
// Collection filter widget
|
||||||
QActionGroup *collection_view_group = new QActionGroup(this);
|
QActionGroup *collection_view_group = new QActionGroup(this);
|
||||||
@@ -529,7 +541,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, SLOT(PlaylistCopyToCollection()));
|
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, SLOT(PlaylistCopyToCollection()));
|
||||||
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, SLOT(PlaylistMoveToCollection()));
|
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, SLOT(PlaylistMoveToCollection()));
|
||||||
//playlist_organise_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(PlaylistMoveToCollection()));
|
//playlist_organise_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organise files..."), this, SLOT(PlaylistMoveToCollection()));
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
playlist_copy_to_device_ = playlist_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(PlaylistCopyToDevice()));
|
playlist_copy_to_device_ = playlist_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, SLOT(PlaylistCopyToDevice()));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
//playlist_delete_ = playlist_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(PlaylistDelete()));
|
//playlist_delete_ = playlist_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, SLOT(PlaylistDelete()));
|
||||||
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser()));
|
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, SLOT(PlaylistOpenInBrowser()));
|
||||||
@@ -551,7 +565,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
|||||||
|
|
||||||
connect(ui_->playlist, SIGNAL(UndoRedoActionsChanged(QAction*, QAction*)), SLOT(PlaylistUndoRedoChanged(QAction*, QAction*)));
|
connect(ui_->playlist, SIGNAL(UndoRedoActionsChanged(QAction*, QAction*)), SLOT(PlaylistUndoRedoChanged(QAction*, QAction*)));
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||||
playlist_copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
playlist_copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
||||||
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), playlist_copy_to_device_, SLOT(setDisabled(bool)));
|
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)), playlist_copy_to_device_, SLOT(setDisabled(bool)));
|
||||||
#endif
|
#endif
|
||||||
@@ -817,8 +831,8 @@ void MainWindow::MediaStopped() {
|
|||||||
tray_icon_->SetProgress(0);
|
tray_icon_->SetProgress(0);
|
||||||
tray_icon_->SetStopped();
|
tray_icon_->SetStopped();
|
||||||
|
|
||||||
song_playing_ = song_empty_;
|
song_playing_ = Song();
|
||||||
song_ = song_empty_;
|
song_ = Song();
|
||||||
image_original_ = QImage();
|
image_original_ = QImage();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1324,7 +1338,9 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
|||||||
playlist_copy_to_collection_->setVisible(false);
|
playlist_copy_to_collection_->setVisible(false);
|
||||||
playlist_move_to_collection_->setVisible(false);
|
playlist_move_to_collection_->setVisible(false);
|
||||||
//playlist_organise_->setVisible(false);
|
//playlist_organise_->setVisible(false);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
playlist_copy_to_device_->setVisible(false);
|
playlist_copy_to_device_->setVisible(false);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
playlist_open_in_browser_->setVisible(false);
|
playlist_open_in_browser_->setVisible(false);
|
||||||
|
|
||||||
@@ -1393,7 +1409,7 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
|
||||||
playlist_copy_to_device_->setVisible(editable);
|
playlist_copy_to_device_->setVisible(editable);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1830,6 +1846,7 @@ void MainWindow::MoveFilesToCollection(const QList<QUrl> &urls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
|
void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||||
organise_dialog_->SetCopy(true);
|
organise_dialog_->SetCopy(true);
|
||||||
if (organise_dialog_->SetUrls(urls))
|
if (organise_dialog_->SetUrls(urls))
|
||||||
@@ -1837,6 +1854,7 @@ void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
|
|||||||
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"));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1968,15 +1986,14 @@ void MainWindow::PlaylistSkip() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GSTREAMER
|
#if defined(HAVE_GSTREAMER)
|
||||||
void MainWindow::PlaylistCopyToDevice() {
|
void MainWindow::PlaylistCopyToDevice() {
|
||||||
|
#if !defined(Q_OS_WIN)
|
||||||
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
QModelIndexList proxy_indexes = ui_->playlist->view()->selectionModel()->selectedRows();
|
||||||
SongList songs;
|
SongList songs;
|
||||||
|
|
||||||
for (const QModelIndex &proxy_index : proxy_indexes) {
|
for (const QModelIndex &proxy_index : proxy_indexes) {
|
||||||
QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
QModelIndex index = app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||||
|
|
||||||
songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
songs << app_->playlist_manager()->current()->item_at(index.row())->Metadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1985,9 +2002,9 @@ void MainWindow::PlaylistCopyToDevice() {
|
|||||||
if (organise_dialog_->SetSongs(songs))
|
if (organise_dialog_->SetSongs(songs))
|
||||||
organise_dialog_->show();
|
organise_dialog_->show();
|
||||||
else {
|
else {
|
||||||
QMessageBox::warning(this, tr("Error"),
|
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
|
||||||
tr("None of the selected songs were suitable for copying to a device"));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -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, Jonas Kvinge <jonas@strawbs.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
|
||||||
@@ -63,8 +64,10 @@ class ContextView;
|
|||||||
class CollectionViewContainer;
|
class CollectionViewContainer;
|
||||||
class AlbumCoverChoiceController;
|
class AlbumCoverChoiceController;
|
||||||
class CommandlineOptions;
|
class CommandlineOptions;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
class DeviceView;
|
class DeviceView;
|
||||||
class DeviceViewContainer;
|
class DeviceViewContainer;
|
||||||
|
#endif
|
||||||
class EditTagDialog;
|
class EditTagDialog;
|
||||||
class Equalizer;
|
class Equalizer;
|
||||||
class ErrorDialog;
|
class ErrorDialog;
|
||||||
@@ -134,7 +137,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
void resizeEvent(QResizeEvent *event);
|
void resizeEvent(QResizeEvent *event);
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN
|
||||||
bool winEvent(MSG *message, long *result);
|
bool winEvent(MSG *message, long *result);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -183,7 +186,9 @@ signals:
|
|||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
void PlaylistCopyToCollection();
|
void PlaylistCopyToCollection();
|
||||||
void PlaylistMoveToCollection();
|
void PlaylistMoveToCollection();
|
||||||
|
#ifndef Q_OS_WIN_
|
||||||
void PlaylistCopyToDevice();
|
void PlaylistCopyToDevice();
|
||||||
|
#endif
|
||||||
void PlaylistOrganiseSelected(bool copy);
|
void PlaylistOrganiseSelected(bool copy);
|
||||||
#endif
|
#endif
|
||||||
//void PlaylistDelete();
|
//void PlaylistDelete();
|
||||||
@@ -202,7 +207,9 @@ signals:
|
|||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
void CopyFilesToCollection(const QList<QUrl>& urls);
|
void CopyFilesToCollection(const QList<QUrl>& urls);
|
||||||
void MoveFilesToCollection(const QList<QUrl>& urls);
|
void MoveFilesToCollection(const QList<QUrl>& urls);
|
||||||
|
//#ifndef Q_OS_WIN
|
||||||
void CopyFilesToDevice(const QList<QUrl>& urls);
|
void CopyFilesToDevice(const QList<QUrl>& urls);
|
||||||
|
//#endif
|
||||||
#endif
|
#endif
|
||||||
void EditFileTags(const QList<QUrl>& urls);
|
void EditFileTags(const QList<QUrl>& urls);
|
||||||
|
|
||||||
@@ -308,8 +315,10 @@ signals:
|
|||||||
ContextView *context_view_;
|
ContextView *context_view_;
|
||||||
CollectionViewContainer *collection_view_;
|
CollectionViewContainer *collection_view_;
|
||||||
FileView *file_view_;
|
FileView *file_view_;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
DeviceViewContainer *device_view_container_;
|
DeviceViewContainer *device_view_container_;
|
||||||
DeviceView *device_view_;
|
DeviceView *device_view_;
|
||||||
|
#endif
|
||||||
PlaylistListContainer *playlist_list_;
|
PlaylistListContainer *playlist_list_;
|
||||||
|
|
||||||
Lazy<SettingsDialog> settings_dialog_;
|
Lazy<SettingsDialog> settings_dialog_;
|
||||||
@@ -347,7 +356,9 @@ signals:
|
|||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
QAction *playlist_copy_to_collection_;
|
QAction *playlist_copy_to_collection_;
|
||||||
QAction *playlist_move_to_collection_;
|
QAction *playlist_move_to_collection_;
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
QAction *playlist_copy_to_device_;
|
QAction *playlist_copy_to_device_;
|
||||||
|
#endif
|
||||||
//QAction *playlist_delete_;
|
//QAction *playlist_delete_;
|
||||||
#endif
|
#endif
|
||||||
QAction *playlist_open_in_browser_;
|
QAction *playlist_open_in_browser_;
|
||||||
@@ -378,7 +389,6 @@ signals:
|
|||||||
|
|
||||||
Song song_;
|
Song song_;
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
Song song_empty_;
|
|
||||||
QImage image_original_;
|
QImage image_original_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -224,14 +224,29 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
|||||||
|
|
||||||
qLog(Debug) << "URL handler for" << result.original_url_ << "returned" << result.media_url_;
|
qLog(Debug) << "URL handler for" << result.original_url_ << "returned" << result.media_url_;
|
||||||
|
|
||||||
|
Song song = item->Metadata();
|
||||||
|
bool update(false);
|
||||||
|
|
||||||
|
// If there was no filetype in the song's metadata, use the one provided by URL handler, if there is one
|
||||||
|
if (
|
||||||
|
(item->Metadata().filetype() == Song::FileType_Unknown && result.filetype_ != Song::FileType_Unknown)
|
||||||
|
||
|
||||||
|
(item->Metadata().filetype() == Song::FileType_Stream && result.filetype_ != Song::FileType_Stream)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
song.set_filetype(result.filetype_);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
// If there was no length info in song's metadata, use the one provided by URL handler, if there is one
|
// If there was no length info in song's metadata, use the one provided by URL handler, if there is one
|
||||||
if (item->Metadata().length_nanosec() <= 0 && result.length_nanosec_ != -1) {
|
if (item->Metadata().length_nanosec() <= 0 && result.length_nanosec_ != -1) {
|
||||||
Song song = item->Metadata();
|
|
||||||
song.set_length_nanosec(result.length_nanosec_);
|
song.set_length_nanosec(result.length_nanosec_);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
item->SetTemporaryMetadata(song);
|
item->SetTemporaryMetadata(song);
|
||||||
app_->playlist_manager()->active()->InformOfCurrentSongChange();
|
app_->playlist_manager()->active()->InformOfCurrentSongChange();
|
||||||
}
|
}
|
||||||
engine_->Play(result.media_url_, stream_change_type_, item->Metadata().has_cue(), item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec());
|
engine_->Play(result.media_url_, result.original_url_, stream_change_type_, item->Metadata().has_cue(), item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec());
|
||||||
|
|
||||||
current_item_ = item;
|
current_item_ = item;
|
||||||
loading_async_ = QUrl();
|
loading_async_ = QUrl();
|
||||||
@@ -245,6 +260,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
|||||||
loading_async_ = result.original_url_;
|
loading_async_ = result.original_url_;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::Next() { NextInternal(Engine::Manual); }
|
void Player::Next() { NextInternal(Engine::Manual); }
|
||||||
@@ -492,8 +508,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
loading_async_ = QUrl();
|
loading_async_ = QUrl();
|
||||||
engine_->Play(current_item_->Url(), change, current_item_->Metadata().has_cue(), current_item_->Metadata().beginning_nanosec(), current_item_->Metadata().end_nanosec());
|
engine_->Play(current_item_->Url(), current_item_->Url(), change, current_item_->Metadata().has_cue(), current_item_->Metadata().beginning_nanosec(), current_item_->Metadata().end_nanosec());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -531,10 +546,12 @@ void Player::SeekBackward() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle) {
|
void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle) {
|
||||||
|
|
||||||
PlaylistItemPtr item = app_->playlist_manager()->active()->current_item();
|
PlaylistItemPtr item = app_->playlist_manager()->active()->current_item();
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
|
if (bundle.url != item->Metadata().url()) return;
|
||||||
|
|
||||||
Engine::SimpleMetaBundle bundle_copy = bundle;
|
Engine::SimpleMetaBundle bundle_copy = bundle;
|
||||||
|
|
||||||
// Maybe the metadata is from icycast and has "Artist - Title" shoved together in the title field.
|
// Maybe the metadata is from icycast and has "Artist - Title" shoved together in the title field.
|
||||||
@@ -545,7 +562,8 @@ void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle) {
|
|||||||
if (space_dash_pos != -1) {
|
if (space_dash_pos != -1) {
|
||||||
bundle_copy.artist = bundle_copy.title.left(space_dash_pos).trimmed();
|
bundle_copy.artist = bundle_copy.title.left(space_dash_pos).trimmed();
|
||||||
bundle_copy.title = bundle_copy.title.mid(space_dash_pos + 3).trimmed();
|
bundle_copy.title = bundle_copy.title.mid(space_dash_pos + 3).trimmed();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
bundle_copy.artist = bundle_copy.title.left(dash_pos).trimmed();
|
bundle_copy.artist = bundle_copy.title.left(dash_pos).trimmed();
|
||||||
bundle_copy.title = bundle_copy.title.mid(dash_pos + 1).trimmed();
|
bundle_copy.title = bundle_copy.title.mid(dash_pos + 1).trimmed();
|
||||||
}
|
}
|
||||||
@@ -661,7 +679,7 @@ void Player::TrackAboutToEnd() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
engine_->StartPreloading(url, next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec());
|
engine_->StartPreloading(url, next_item->Url(), next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +700,7 @@ void Player::InvalidSongRequested(const QUrl &url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::RegisterUrlHandler(UrlHandler *handler) {
|
void Player::RegisterUrlHandler(UrlHandler *handler) {
|
||||||
|
|
||||||
const QString scheme = handler->scheme();
|
const QString scheme = handler->scheme();
|
||||||
|
|
||||||
if (url_handlers_.contains(scheme)) {
|
if (url_handlers_.contains(scheme)) {
|
||||||
@@ -698,7 +716,7 @@ void Player::RegisterUrlHandler(UrlHandler *handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::UnregisterUrlHandler(UrlHandler *handler) {
|
void Player::UnregisterUrlHandler(UrlHandler *handler) {
|
||||||
|
|
||||||
const QString scheme = url_handlers_.key(handler);
|
const QString scheme = url_handlers_.key(handler);
|
||||||
if (scheme.isEmpty()) {
|
if (scheme.isEmpty()) {
|
||||||
qLog(Warning) << "Tried to unregister a URL handler for" << handler->scheme() << "that wasn't registered";
|
qLog(Warning) << "Tried to unregister a URL handler for" << handler->scheme() << "that wasn't registered";
|
||||||
|
|||||||
@@ -996,12 +996,12 @@ void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
|
|||||||
if (!bundle.album.isEmpty()) d->album_ = bundle.album;
|
if (!bundle.album.isEmpty()) d->album_ = bundle.album;
|
||||||
if (!bundle.comment.isEmpty()) d->comment_ = bundle.comment;
|
if (!bundle.comment.isEmpty()) d->comment_ = bundle.comment;
|
||||||
if (!bundle.genre.isEmpty()) d->genre_ = bundle.genre;
|
if (!bundle.genre.isEmpty()) d->genre_ = bundle.genre;
|
||||||
if (!bundle.bitrate.isEmpty()) d->bitrate_ = bundle.bitrate.toInt();
|
if (bundle.bitrate > 0) d->bitrate_ = bundle.bitrate;
|
||||||
if (!bundle.samplerate.isEmpty()) d->samplerate_ = bundle.samplerate.toInt();
|
if (bundle.samplerate > 0) d->samplerate_ = bundle.samplerate;
|
||||||
if (!bundle.bitdepth.isEmpty()) d->samplerate_ = bundle.bitdepth.toInt();
|
if (bundle.bitdepth > 0) d->samplerate_ = bundle.bitdepth;
|
||||||
if (!bundle.length.isEmpty()) set_length_nanosec(bundle.length.toLongLong());
|
if (bundle.length > 0) set_length_nanosec(bundle.length);
|
||||||
if (!bundle.year.isEmpty()) d->year_ = bundle.year.toInt();
|
if (bundle.year > 0) d->year_ = bundle.year;
|
||||||
if (!bundle.tracknr.isEmpty()) d->track_ = bundle.tracknr.toInt();
|
if (bundle.tracknr > 0) d->track_ = bundle.tracknr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ class Song {
|
|||||||
|
|
||||||
void set_image(const QImage &i);
|
void set_image(const QImage &i);
|
||||||
|
|
||||||
|
|
||||||
// Comparison functions
|
// Comparison functions
|
||||||
bool IsMetadataEqual(const Song &other) const;
|
bool IsMetadataEqual(const Song &other) const;
|
||||||
bool IsOnSameAlbum(const Song &other) const;
|
bool IsOnSameAlbum(const Song &other) const;
|
||||||
|
|||||||
@@ -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 2018, 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
|
||||||
@@ -23,12 +24,10 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
|
#include "song.h"
|
||||||
#include "urlhandler.h"
|
#include "urlhandler.h"
|
||||||
|
|
||||||
UrlHandler::LoadResult::LoadResult(const QUrl &original_url, Type type, const QUrl &media_url, qint64 length_nanosec) : original_url_(original_url), type_(type), media_url_(media_url), length_nanosec_(length_nanosec) {}
|
UrlHandler::LoadResult::LoadResult(const QUrl &original_url, Type type, const QUrl &media_url, const Song::FileType &filetype, qint64 length_nanosec) : original_url_(original_url), type_(type), media_url_(media_url), filetype_(filetype), length_nanosec_(length_nanosec) {}
|
||||||
|
|
||||||
UrlHandler::UrlHandler(QObject *parent) : QObject(parent) {}
|
UrlHandler::UrlHandler(QObject *parent) : QObject(parent) {}
|
||||||
|
|
||||||
QIcon UrlHandler::icon() const { return QIcon(); }
|
|
||||||
|
|||||||
@@ -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 2018, 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,7 +28,8 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QIcon>
|
|
||||||
|
#include "song.h"
|
||||||
|
|
||||||
class UrlHandler : public QObject {
|
class UrlHandler : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -37,7 +39,6 @@ class UrlHandler : public QObject {
|
|||||||
|
|
||||||
// The URL scheme that this handler handles.
|
// The URL scheme that this handler handles.
|
||||||
virtual QString scheme() const = 0;
|
virtual QString scheme() const = 0;
|
||||||
virtual QIcon icon() const;
|
|
||||||
|
|
||||||
// Returned by StartLoading() and LoadNext(), indicates what the player should do when it wants to load a URL.
|
// Returned by StartLoading() and LoadNext(), indicates what the player should do when it wants to load a URL.
|
||||||
struct LoadResult {
|
struct LoadResult {
|
||||||
@@ -53,7 +54,7 @@ class UrlHandler : public QObject {
|
|||||||
TrackAvailable,
|
TrackAvailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
LoadResult(const QUrl &original_url = QUrl(), Type type = NoMoreTracks, const QUrl &media_url = QUrl(), qint64 length_nanosec_ = -1);
|
LoadResult(const QUrl &original_url = QUrl(), Type type = NoMoreTracks, const QUrl &media_url = QUrl(), const Song::FileType &filetype = Song::FileType_Stream, qint64 length_nanosec_ = -1);
|
||||||
|
|
||||||
// The url that the playlist item has in Url().
|
// The url that the playlist item has in Url().
|
||||||
// Might be something unplayable like lastfm://...
|
// Might be something unplayable like lastfm://...
|
||||||
@@ -64,6 +65,9 @@ class UrlHandler : public QObject {
|
|||||||
// The actual url to something that gstreamer can play.
|
// The actual url to something that gstreamer can play.
|
||||||
QUrl media_url_;
|
QUrl media_url_;
|
||||||
|
|
||||||
|
// The type of the stream
|
||||||
|
Song::FileType filetype_;
|
||||||
|
|
||||||
// Track length, if we are able to get it only now
|
// Track length, if we are able to get it only now
|
||||||
qint64 length_nanosec_;
|
qint64 length_nanosec_;
|
||||||
};
|
};
|
||||||
@@ -78,8 +82,9 @@ class UrlHandler : public QObject {
|
|||||||
virtual void TrackAboutToEnd() {};
|
virtual void TrackAboutToEnd() {};
|
||||||
virtual void TrackSkipped() {};
|
virtual void TrackSkipped() {};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AsyncLoadComplete(const UrlHandler::LoadResult &result);
|
void AsyncLoadComplete(const UrlHandler::LoadResult &result);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // URLHANDLER_H
|
#endif // URLHANDLER_H
|
||||||
|
|||||||
@@ -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 2018, 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
|
||||||
@@ -690,21 +691,6 @@ bool IsLaptop() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SystemLanguageName() {
|
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040800
|
|
||||||
QString system_language = QLocale::system().uiLanguages().empty() ? QLocale::system().name() : QLocale::system().uiLanguages().first();
|
|
||||||
// uiLanguages returns strings with "-" as separators for language/region;
|
|
||||||
// however QTranslator needs "_" separators
|
|
||||||
system_language.replace("-", "_");
|
|
||||||
#else
|
|
||||||
QString system_language = QLocale::system().name();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return system_language;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UrlOnSameDriveAsStrawberry(const QUrl &url) {
|
bool UrlOnSameDriveAsStrawberry(const QUrl &url) {
|
||||||
|
|
||||||
if (url.scheme() != "file") return false;
|
if (url.scheme() != "file") return false;
|
||||||
@@ -723,18 +709,13 @@ bool UrlOnSameDriveAsStrawberry(const QUrl &url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QUrl GetRelativePathToStrawberryBin(const QUrl &url) {
|
QUrl GetRelativePathToStrawberryBin(const QUrl &url) {
|
||||||
|
|
||||||
QDir appPath(QCoreApplication::applicationDirPath());
|
QDir appPath(QCoreApplication::applicationDirPath());
|
||||||
return QUrl::fromLocalFile(appPath.relativeFilePath(url.toLocalFile()));
|
return QUrl::fromLocalFile(appPath.relativeFilePath(url.toLocalFile()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathWithoutFilenameExtension(const QString &filename) {
|
QString PathWithoutFilenameExtension(const QString &filename) {
|
||||||
|
if (filename.section('/', -1, -1).contains('.')) return filename.section('.', 0, -2);
|
||||||
if (filename.section('/', -1, -1).contains('.'))
|
|
||||||
return filename.section('.', 0, -2);
|
|
||||||
return filename;
|
return filename;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FiddleFileExtension(const QString &filename, const QString &new_extension) {
|
QString FiddleFileExtension(const QString &filename, const QString &new_extension) {
|
||||||
@@ -786,6 +767,28 @@ void CheckPortable() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString GetRandomStringWithChars(const int len) {
|
||||||
|
const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||||
|
return GetRandomString(len, UseCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GetRandomStringWithCharsAndNumbers(const int len) {
|
||||||
|
const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||||
|
return GetRandomString(len, UseCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GetRandomString(const int len, const QString &UseCharacters) {
|
||||||
|
|
||||||
|
QString randstr;
|
||||||
|
for(int i=0 ; i < len ; ++i) {
|
||||||
|
int index = qrand() % UseCharacters.length();
|
||||||
|
QChar nextchar = UseCharacters.at(index);
|
||||||
|
randstr.append(nextchar);
|
||||||
|
}
|
||||||
|
return randstr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utilities
|
} // namespace Utilities
|
||||||
|
|
||||||
ScopedWCharArray::ScopedWCharArray(const QString &str)
|
ScopedWCharArray::ScopedWCharArray(const QString &str)
|
||||||
|
|||||||
@@ -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 2018, 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
|
||||||
@@ -149,7 +150,10 @@ int GetThreadId();
|
|||||||
// Returns true if this machine has a battery.
|
// Returns true if this machine has a battery.
|
||||||
bool IsLaptop();
|
bool IsLaptop();
|
||||||
|
|
||||||
QString SystemLanguageName();
|
QString GetRandomStringWithChars(const int len);
|
||||||
|
QString GetRandomStringWithCharsAndNumbers(const int len);
|
||||||
|
QString GetRandomString(const int len, const QString &UseCharacters);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScopedWCharArray {
|
class ScopedWCharArray {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ void DeviceItemDelegate::paint(QPainter *p, const QStyleOptionViewItem &opt, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw the background
|
// Draw the background
|
||||||
const QStyleOptionViewItemV3 *vopt = qstyleoption_cast<const QStyleOptionViewItemV3*>(&opt);
|
const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem*>(&opt);
|
||||||
const QWidget *widget = vopt->widget;
|
const QWidget *widget = vopt->widget;
|
||||||
QStyle *style = widget->style() ? widget->style() : QApplication::style();
|
QStyle *style = widget->style() ? widget->style() : QApplication::style();
|
||||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, widget);
|
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, widget);
|
||||||
|
|||||||
@@ -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, Jonas Kvinge <jonas@strawbs.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
|
||||||
|
|||||||
@@ -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, Jonas Kvinge <jonas@strawbs.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
|
||||||
|
|||||||
@@ -99,10 +99,13 @@ QList<DeviceFinder::Device> AlsaDeviceFinder::ListDevices() {
|
|||||||
|
|
||||||
Device device;
|
Device device;
|
||||||
device.description = QString("%1 %2").arg(snd_ctl_card_info_get_name(cardinfo)).arg(snd_pcm_info_get_name(pcminfo));
|
device.description = QString("%1 %2").arg(snd_ctl_card_info_get_name(cardinfo)).arg(snd_pcm_info_get_name(pcminfo));
|
||||||
device.value = QString("hw:%1,%2").arg(card).arg(dev);
|
|
||||||
device.iconname = GuessIconName(device.description);
|
device.iconname = GuessIconName(device.description);
|
||||||
device.card = card;
|
device.card = card;
|
||||||
device.device = dev;
|
device.device = dev;
|
||||||
|
|
||||||
|
device.value = QString("hw:%1,%2").arg(card).arg(dev);
|
||||||
|
ret.append(device);
|
||||||
|
device.value = QString("plughw:%1,%2").arg(card).arg(dev);
|
||||||
ret.append(device);
|
ret.append(device);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,11 +60,12 @@ Engine::Base::Base()
|
|||||||
|
|
||||||
Engine::Base::~Base() {}
|
Engine::Base::~Base() {}
|
||||||
|
|
||||||
bool Engine::Base::Load(const QUrl &url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool Engine::Base::Load(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
Q_UNUSED(force_stop_at_end);
|
Q_UNUSED(force_stop_at_end);
|
||||||
|
|
||||||
url_ = url;
|
media_url_ = media_url;
|
||||||
|
original_url_ = original_url;
|
||||||
beginning_nanosec_ = beginning_nanosec;
|
beginning_nanosec_ = beginning_nanosec;
|
||||||
end_nanosec_ = end_nanosec;
|
end_nanosec_ = end_nanosec;
|
||||||
|
|
||||||
@@ -73,12 +74,13 @@ bool Engine::Base::Load(const QUrl &url, TrackChangeFlags, bool force_stop_at_en
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Engine::Base::Play(const QUrl &url, TrackChangeFlags flags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool Engine::Base::Play(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags flags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
if (!Load(url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
|
if (!Load(media_url, original_url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return Play(0);
|
return Play(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Base::SetVolume(uint value) {
|
void Engine::Base::SetVolume(uint value) {
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ public:
|
|||||||
|
|
||||||
virtual bool Init() = 0;
|
virtual bool Init() = 0;
|
||||||
virtual State state() const = 0;
|
virtual State state() const = 0;
|
||||||
virtual void StartPreloading(const QUrl&, bool, qint64, qint64) {}
|
virtual void StartPreloading(const QUrl &media_url, const QUrl &original_url, bool, qint64, qint64) {}
|
||||||
virtual bool Load(const QUrl &url, TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
virtual bool Load(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
virtual bool Play(quint64 offset_nanosec) = 0;
|
virtual bool Play(quint64 offset_nanosec) = 0;
|
||||||
virtual void Stop(bool stop_after = false) = 0;
|
virtual void Stop(bool stop_after = false) = 0;
|
||||||
virtual void Pause() = 0;
|
virtual void Pause() = 0;
|
||||||
@@ -93,10 +93,11 @@ public:
|
|||||||
virtual bool ValidOutput(const QString &output) = 0;
|
virtual bool ValidOutput(const QString &output) = 0;
|
||||||
virtual QString DefaultOutput() = 0;
|
virtual QString DefaultOutput() = 0;
|
||||||
virtual bool CustomDeviceSupport(const QString &output) = 0;
|
virtual bool CustomDeviceSupport(const QString &output) = 0;
|
||||||
|
virtual bool ALSADeviceSupport(const QString &output) = 0;
|
||||||
|
|
||||||
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
|
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
|
||||||
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
|
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
|
||||||
bool Play(const QUrl &u, TrackChangeFlags c, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
bool Play(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags c, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
void SetVolume(uint value);
|
void SetVolume(uint value);
|
||||||
static uint MakeVolumeLogarithmic(uint volume);
|
static uint MakeVolumeLogarithmic(uint volume);
|
||||||
|
|
||||||
@@ -163,7 +164,8 @@ protected:
|
|||||||
uint volume_;
|
uint volume_;
|
||||||
quint64 beginning_nanosec_;
|
quint64 beginning_nanosec_;
|
||||||
qint64 end_nanosec_;
|
qint64 end_nanosec_;
|
||||||
QUrl url_;
|
QUrl media_url_;
|
||||||
|
QUrl original_url_;
|
||||||
Scope scope_;
|
Scope scope_;
|
||||||
bool buffering_;
|
bool buffering_;
|
||||||
bool equalizer_enabled_;
|
bool equalizer_enabled_;
|
||||||
@@ -202,17 +204,19 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SimpleMetaBundle {
|
struct SimpleMetaBundle {
|
||||||
|
QUrl url;
|
||||||
QString title;
|
QString title;
|
||||||
QString artist;
|
QString artist;
|
||||||
QString album;
|
QString album;
|
||||||
QString comment;
|
QString comment;
|
||||||
QString genre;
|
QString genre;
|
||||||
QString bitrate;
|
qlonglong length;
|
||||||
QString samplerate;
|
int year;
|
||||||
QString bitdepth;
|
int tracknr;
|
||||||
QString length;
|
int samplerate;
|
||||||
QString year;
|
int bitdepth;
|
||||||
QString tracknr;
|
qlonglong bitrate;
|
||||||
|
QString lyrics;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -25,39 +25,35 @@
|
|||||||
#include "enginetype.h"
|
#include "enginetype.h"
|
||||||
|
|
||||||
namespace Engine {
|
namespace Engine {
|
||||||
|
|
||||||
Engine::EngineType EngineTypeFromName(QString enginename) {
|
Engine::EngineType EngineTypeFromName(QString enginename) {
|
||||||
|
|
||||||
QString lower = enginename.toLower();
|
QString lower = enginename.toLower();
|
||||||
|
if (lower == "xine") return Engine::Xine;
|
||||||
if (lower == "xine") return Engine::Xine;
|
else if (lower == "gstreamer") return Engine::GStreamer;
|
||||||
else if (lower == "gstreamer") return Engine::GStreamer;
|
else if (lower == "phonon") return Engine::Phonon;
|
||||||
else if (lower == "phonon") return Engine::Phonon;
|
else if (lower == "vlc") return Engine::VLC;
|
||||||
else if (lower == "vlc") return Engine::VLC;
|
else return Engine::None;
|
||||||
else return Engine::None;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EngineName(Engine::EngineType enginetype) {
|
QString EngineName(Engine::EngineType enginetype) {
|
||||||
switch (enginetype) {
|
switch (enginetype) {
|
||||||
case Engine::Xine: return QObject::tr("xine");
|
case Engine::Xine: return QString("xine");
|
||||||
case Engine::GStreamer: return QObject::tr("gstreamer");
|
case Engine::GStreamer: return QString("gstreamer");
|
||||||
case Engine::Phonon: return QObject::tr("phonon");
|
case Engine::Phonon: return QString("phonon");
|
||||||
case Engine::VLC: return QObject::tr("vlc");
|
case Engine::VLC: return QString("vlc");
|
||||||
case Engine::None:
|
case Engine::None:
|
||||||
default: return QObject::tr("None");
|
default: return QString("None");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EngineDescription(Engine::EngineType enginetype) {
|
QString EngineDescription(Engine::EngineType enginetype) {
|
||||||
switch (enginetype) {
|
switch (enginetype) {
|
||||||
case Engine::Xine: return QObject::tr("Xine");
|
case Engine::Xine: return QString("Xine");
|
||||||
case Engine::GStreamer: return QObject::tr("GStreamer");
|
case Engine::GStreamer: return QString("GStreamer");
|
||||||
case Engine::Phonon: return QObject::tr("Phonon");
|
case Engine::Phonon: return QString("Phonon");
|
||||||
case Engine::VLC: return QObject::tr("VLC");
|
case Engine::VLC: return QString("VLC");
|
||||||
case Engine::None:
|
case Engine::None:
|
||||||
default: return QObject::tr("None");
|
default: return QString("None");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ bool GstEngine::Init() {
|
|||||||
|
|
||||||
Engine::State GstEngine::state() const {
|
Engine::State GstEngine::state() const {
|
||||||
|
|
||||||
if (!current_pipeline_) return url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
if (!current_pipeline_) return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||||
|
|
||||||
switch (current_pipeline_->state()) {
|
switch (current_pipeline_->state()) {
|
||||||
case GST_STATE_NULL:
|
case GST_STATE_NULL:
|
||||||
@@ -154,32 +154,32 @@ Engine::State GstEngine::state() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::StartPreloading(const QUrl &url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
|
void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
EnsureInitialised();
|
EnsureInitialised();
|
||||||
|
|
||||||
QByteArray gst_url = FixupUrl(url);
|
QByteArray gst_url = FixupUrl(media_url);
|
||||||
|
|
||||||
// No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully)
|
// No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully)
|
||||||
if (current_pipeline_)
|
if (current_pipeline_)
|
||||||
current_pipeline_->SetNextUrl(gst_url, beginning_nanosec, force_stop_at_end ? end_nanosec : 0);
|
current_pipeline_->SetNextUrl(gst_url, original_url, beginning_nanosec, force_stop_at_end ? end_nanosec : 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GstEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool GstEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
EnsureInitialised();
|
EnsureInitialised();
|
||||||
|
|
||||||
Engine::Base::Load(url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||||
|
|
||||||
QByteArray gst_url = FixupUrl(url);
|
QByteArray gst_url = FixupUrl(media_url);
|
||||||
|
|
||||||
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & Engine::Manual) || (autocrossfade_enabled_ && change & Engine::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & Engine::Intro));
|
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & Engine::Manual) || (autocrossfade_enabled_ && change & Engine::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & Engine::Intro));
|
||||||
|
|
||||||
if (change & Engine::Auto && change & Engine::SameAlbum && !crossfade_same_album_)
|
if (change & Engine::Auto && change & Engine::SameAlbum && !crossfade_same_album_)
|
||||||
crossfade = false;
|
crossfade = false;
|
||||||
|
|
||||||
if (!crossfade && current_pipeline_ && current_pipeline_->url() == gst_url && change & Engine::Auto) {
|
if (!crossfade && current_pipeline_ && current_pipeline_->media_url() == gst_url && change & Engine::Auto) {
|
||||||
// We're not crossfading, and the pipeline is already playing the URI we want, so just do nothing.
|
// We're not crossfading, and the pipeline is already playing the URI we want, so just do nothing.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ bool GstEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool forc
|
|||||||
//SetEqualizerParameters(equalizer_preamp_, equalizer_gains_);
|
//SetEqualizerParameters(equalizer_preamp_, equalizer_gains_);
|
||||||
//SetStereoBalance(stereo_balance_);
|
//SetStereoBalance(stereo_balance_);
|
||||||
|
|
||||||
shared_ptr<GstEnginePipeline> pipeline = CreatePipeline(gst_url, force_stop_at_end ? end_nanosec : 0);
|
shared_ptr<GstEnginePipeline> pipeline = CreatePipeline(gst_url, original_url, force_stop_at_end ? end_nanosec : 0);
|
||||||
if (!pipeline) return false;
|
if (!pipeline) return false;
|
||||||
|
|
||||||
if (crossfade) StartFadeout();
|
if (crossfade) StartFadeout();
|
||||||
@@ -229,7 +229,8 @@ void GstEngine::Stop(bool stop_after) {
|
|||||||
|
|
||||||
StopTimers();
|
StopTimers();
|
||||||
|
|
||||||
url_ = QUrl(); // To ensure we return Empty from state()
|
media_url_ = QUrl(); // To ensure we return Empty from state()
|
||||||
|
original_url_ = QUrl();
|
||||||
beginning_nanosec_ = end_nanosec_ = 0;
|
beginning_nanosec_ = end_nanosec_ = 0;
|
||||||
|
|
||||||
// Check if we started a fade out. If it isn't finished yet and the user pressed stop, we cancel the fader and just stop the playback.
|
// Check if we started a fade out. If it isn't finished yet and the user pressed stop, we cancel the fader and just stop the playback.
|
||||||
@@ -402,6 +403,10 @@ bool GstEngine::CustomDeviceSupport(const QString &output) {
|
|||||||
return (output == kALSASink || output == kOpenALSASink || output == kOSSSink || output == kOSS4Sink || output == kPulseSink || output == kA2DPSink || output == kAVDTPSink);
|
return (output == kALSASink || output == kOpenALSASink || output == kOSSSink || output == kOSS4Sink || output == kPulseSink || output == kA2DPSink || output == kAVDTPSink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GstEngine::ALSADeviceSupport(const QString &output) {
|
||||||
|
return (output == kALSASink);
|
||||||
|
}
|
||||||
|
|
||||||
void GstEngine::ReloadSettings() {
|
void GstEngine::ReloadSettings() {
|
||||||
|
|
||||||
Engine::Base::ReloadSettings();
|
Engine::Base::ReloadSettings();
|
||||||
@@ -571,7 +576,7 @@ void GstEngine::HandlePipelineError(int pipeline_id, const QString &message, int
|
|||||||
BufferingFinished();
|
BufferingFinished();
|
||||||
emit StateChanged(Engine::Error);
|
emit StateChanged(Engine::Error);
|
||||||
// unable to play media stream with this url
|
// unable to play media stream with this url
|
||||||
emit InvalidSongRequested(url_);
|
emit InvalidSongRequested(media_url_);
|
||||||
|
|
||||||
emit Error(message);
|
emit Error(message);
|
||||||
|
|
||||||
@@ -645,9 +650,9 @@ void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 off
|
|||||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||||
// Failure, but we got a redirection URL - try loading that instead
|
// Failure, but we got a redirection URL - try loading that instead
|
||||||
QByteArray redirect_url = current_pipeline_->redirect_url();
|
QByteArray redirect_url = current_pipeline_->redirect_url();
|
||||||
if (!redirect_url.isEmpty() && redirect_url != current_pipeline_->url()) {
|
if (!redirect_url.isEmpty() && redirect_url != current_pipeline_->media_url()) {
|
||||||
qLog(Info) << "Redirecting to" << redirect_url;
|
qLog(Info) << "Redirecting to" << redirect_url;
|
||||||
current_pipeline_ = CreatePipeline(redirect_url, end_nanosec_);
|
current_pipeline_ = CreatePipeline(redirect_url, current_pipeline_->original_url(), end_nanosec_);
|
||||||
Play(offset_nanosec);
|
Play(offset_nanosec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -661,14 +666,14 @@ void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 off
|
|||||||
|
|
||||||
StartTimers();
|
StartTimers();
|
||||||
|
|
||||||
// initial offset
|
// Initial offset
|
||||||
if (offset_nanosec != 0 || beginning_nanosec_ != 0) {
|
if (offset_nanosec != 0 || beginning_nanosec_ != 0) {
|
||||||
Seek(offset_nanosec);
|
Seek(offset_nanosec);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit StateChanged(Engine::Playing);
|
emit StateChanged(Engine::Playing);
|
||||||
// we've successfully started playing a media stream with this url
|
// We've successfully started playing a media stream with this url
|
||||||
emit ValidSongRequested(url_);
|
emit ValidSongRequested(media_url_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,25 +824,14 @@ shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline() {
|
|||||||
connect(ret.get(), SIGNAL(BufferingProgress(int)), SLOT(BufferingProgress(int)));
|
connect(ret.get(), SIGNAL(BufferingProgress(int)), SLOT(BufferingProgress(int)));
|
||||||
connect(ret.get(), SIGNAL(BufferingFinished()), SLOT(BufferingFinished()));
|
connect(ret.get(), SIGNAL(BufferingFinished()), SLOT(BufferingFinished()));
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QUrl &url, qint64 end_nanosec) {
|
|
||||||
|
|
||||||
shared_ptr<GstEnginePipeline> ret = CreatePipeline();
|
|
||||||
|
|
||||||
if (!ret->InitFromUrl(url.toEncoded(), end_nanosec)) ret.reset();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QByteArray &url, qint64 end_nanosec) {
|
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QByteArray &gst_url, const QUrl &original_url, qint64 end_nanosec) {
|
||||||
|
|
||||||
shared_ptr<GstEnginePipeline> ret = CreatePipeline();
|
shared_ptr<GstEnginePipeline> ret = CreatePipeline();
|
||||||
|
if (!ret->InitFromUrl(gst_url, original_url, end_nanosec)) ret.reset();
|
||||||
if (!ret->InitFromUrl(url, end_nanosec)) ret.reset();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
Engine::State state() const;
|
Engine::State state() const;
|
||||||
void StartPreloading(const QUrl &url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec);
|
void StartPreloading(const QUrl &media_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool Load(const QUrl &, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool Play(quint64 offset_nanosec);
|
bool Play(quint64 offset_nanosec);
|
||||||
void Stop(bool stop_after = false);
|
void Stop(bool stop_after = false);
|
||||||
void Pause();
|
void Pause();
|
||||||
@@ -87,6 +87,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
bool ValidOutput(const QString &output);
|
bool ValidOutput(const QString &output);
|
||||||
QString DefaultOutput() { return kAutoSink; }
|
QString DefaultOutput() { return kAutoSink; }
|
||||||
bool CustomDeviceSupport(const QString &output);
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
bool ALSADeviceSupport(const QString &output);
|
||||||
|
|
||||||
void EnsureInitialised() { initialising_.waitForFinished(); }
|
void EnsureInitialised() { initialising_.waitForFinished(); }
|
||||||
void InitialiseGStreamer();
|
void InitialiseGStreamer();
|
||||||
@@ -156,8 +157,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
void StopTimers();
|
void StopTimers();
|
||||||
|
|
||||||
std::shared_ptr<GstEnginePipeline> CreatePipeline();
|
std::shared_ptr<GstEnginePipeline> CreatePipeline();
|
||||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QUrl &url, qint64 end_nanosec);
|
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QByteArray &gst_url, const QUrl &original_url, qint64 end_nanosec);
|
||||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QByteArray &url, qint64 end_nanosec);
|
|
||||||
|
|
||||||
void UpdateScope(int chunk_length);
|
void UpdateScope(int chunk_length);
|
||||||
|
|
||||||
|
|||||||
@@ -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 2018, 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
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
#include <QTimeLine>
|
#include <QTimeLine>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
@@ -351,7 +353,6 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
|
|
||||||
// Let the audio output of the tee autonegotiate the bit depth and format.
|
// Let the audio output of the tee autonegotiate the bit depth and format.
|
||||||
GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
|
GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
|
||||||
|
|
||||||
gst_element_link_filtered(convert, audiosink_, caps);
|
gst_element_link_filtered(convert, audiosink_, caps);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
@@ -371,14 +372,16 @@ bool GstEnginePipeline::InitFromString(const QString &pipeline) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GstEnginePipeline::InitFromUrl(const QByteArray &url, qint64 end_nanosec) {
|
bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec) {
|
||||||
|
|
||||||
|
media_url_ = media_url;
|
||||||
|
original_url_ = original_url;
|
||||||
end_offset_nanosec_ = end_nanosec;
|
end_offset_nanosec_ = end_nanosec;
|
||||||
|
|
||||||
pipeline_ = engine_->CreateElement("playbin");
|
pipeline_ = engine_->CreateElement("playbin");
|
||||||
if (pipeline_ == nullptr) return false;
|
if (pipeline_ == nullptr) return false;
|
||||||
|
|
||||||
g_object_set(G_OBJECT(pipeline_), "uri", url.constData(), nullptr);
|
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
|
||||||
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
|
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
|
||||||
|
|
||||||
CHECKED_GCONNECT(G_OBJECT(pipeline_), "pad-added", &NewPadCallback, this);
|
CHECKED_GCONNECT(G_OBJECT(pipeline_), "pad-added", &NewPadCallback, this);
|
||||||
@@ -500,9 +503,11 @@ void GstEnginePipeline::StreamStartMessageReceived() {
|
|||||||
if (next_uri_set_) {
|
if (next_uri_set_) {
|
||||||
next_uri_set_ = false;
|
next_uri_set_ = false;
|
||||||
|
|
||||||
url_ = next_url_;
|
media_url_ = next_media_url_;
|
||||||
|
original_url_ = next_original_url_;
|
||||||
end_offset_nanosec_ = next_end_offset_nanosec_;
|
end_offset_nanosec_ = next_end_offset_nanosec_;
|
||||||
next_url_ = QByteArray();
|
next_media_url_ = QByteArray();
|
||||||
|
next_original_url_ = QUrl();
|
||||||
next_beginning_offset_nanosec_ = 0;
|
next_beginning_offset_nanosec_ = 0;
|
||||||
next_end_offset_nanosec_ = 0;
|
next_end_offset_nanosec_ = 0;
|
||||||
|
|
||||||
@@ -579,10 +584,18 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
|
|||||||
gst_message_parse_tag(msg, &taglist);
|
gst_message_parse_tag(msg, &taglist);
|
||||||
|
|
||||||
Engine::SimpleMetaBundle bundle;
|
Engine::SimpleMetaBundle bundle;
|
||||||
bundle.title = ParseTag(taglist, GST_TAG_TITLE);
|
bundle.url = original_url_;
|
||||||
bundle.artist = ParseTag(taglist, GST_TAG_ARTIST);
|
bundle.title = ParseStrTag(taglist, GST_TAG_TITLE);
|
||||||
bundle.comment = ParseTag(taglist, GST_TAG_COMMENT);
|
bundle.artist = ParseStrTag(taglist, GST_TAG_ARTIST);
|
||||||
bundle.album = ParseTag(taglist, GST_TAG_ALBUM);
|
bundle.comment = ParseStrTag(taglist, GST_TAG_COMMENT);
|
||||||
|
bundle.album = ParseStrTag(taglist, GST_TAG_ALBUM);
|
||||||
|
bundle.length = 0;
|
||||||
|
bundle.year = 0;
|
||||||
|
bundle.tracknr = 0;
|
||||||
|
bundle.samplerate = 0;
|
||||||
|
bundle.bitdepth = 0;
|
||||||
|
bundle.bitrate = ParseUIntTag(taglist, GST_TAG_BITRATE) / 1000;
|
||||||
|
bundle.lyrics = ParseStrTag(taglist, GST_TAG_LYRICS);
|
||||||
|
|
||||||
gst_tag_list_free(taglist);
|
gst_tag_list_free(taglist);
|
||||||
|
|
||||||
@@ -593,7 +606,7 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GstEnginePipeline::ParseTag(GstTagList *list, const char *tag) const {
|
QString GstEnginePipeline::ParseStrTag(GstTagList *list, const char *tag) const {
|
||||||
|
|
||||||
gchar *data = nullptr;
|
gchar *data = nullptr;
|
||||||
bool success = gst_tag_list_get_string(list, tag, &data);
|
bool success = gst_tag_list_get_string(list, tag, &data);
|
||||||
@@ -607,6 +620,17 @@ QString GstEnginePipeline::ParseTag(GstTagList *list, const char *tag) const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint GstEnginePipeline::ParseUIntTag(GstTagList *list, const char *tag) const {
|
||||||
|
|
||||||
|
guint data;
|
||||||
|
bool success = gst_tag_list_get_uint(list, tag, &data);
|
||||||
|
|
||||||
|
guint ret = 0;
|
||||||
|
if (success && data) ret = data;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
|
void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
|
||||||
|
|
||||||
if (msg->src != GST_OBJECT(pipeline_)) {
|
if (msg->src != GST_OBJECT(pipeline_)) {
|
||||||
@@ -630,7 +654,7 @@ void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
|
|||||||
if (next_uri_set_ && new_state == GST_STATE_READY) {
|
if (next_uri_set_ && new_state == GST_STATE_READY) {
|
||||||
// Revert uri and go back to PLAY state again
|
// Revert uri and go back to PLAY state again
|
||||||
next_uri_set_ = false;
|
next_uri_set_ = false;
|
||||||
g_object_set(G_OBJECT(pipeline_), "uri", url_.constData(), nullptr);
|
g_object_set(G_OBJECT(pipeline_), "uri", media_url_.constData(), nullptr);
|
||||||
SetState(GST_STATE_PLAYING);
|
SetState(GST_STATE_PLAYING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -758,10 +782,11 @@ GstPadProbeReturn GstEnginePipeline::HandoffCallback(GstPad*, GstPadProbeInfo *i
|
|||||||
quint64 end_time = start_time + duration;
|
quint64 end_time = start_time + duration;
|
||||||
|
|
||||||
if (end_time > instance->end_offset_nanosec_) {
|
if (end_time > instance->end_offset_nanosec_) {
|
||||||
if (instance->has_next_valid_url() && instance->next_url_ == instance->url_ && instance->next_beginning_offset_nanosec_ == instance->end_offset_nanosec_) {
|
if (instance->has_next_valid_url() && instance->next_media_url_ == instance->media_url_ && instance->next_beginning_offset_nanosec_ == instance->end_offset_nanosec_) {
|
||||||
// The "next" song is actually the next segment of this file - so cheat and keep on playing, but just tell the Engine we've moved on.
|
// The "next" song is actually the next segment of this file - so cheat and keep on playing, but just tell the Engine we've moved on.
|
||||||
instance->end_offset_nanosec_ = instance->next_end_offset_nanosec_;
|
instance->end_offset_nanosec_ = instance->next_end_offset_nanosec_;
|
||||||
instance->next_url_ = QByteArray();
|
instance->next_media_url_ = QByteArray();
|
||||||
|
instance->next_original_url_ = QUrl();
|
||||||
instance->next_beginning_offset_nanosec_ = 0;
|
instance->next_beginning_offset_nanosec_ = 0;
|
||||||
instance->next_end_offset_nanosec_ = 0;
|
instance->next_end_offset_nanosec_ = 0;
|
||||||
|
|
||||||
@@ -814,7 +839,7 @@ void GstEnginePipeline::AboutToFinishCallback(GstPlayBin *bin, gpointer self) {
|
|||||||
// Set the next uri. When the current song ends it will be played automatically and a STREAM_START message is send to the bus.
|
// Set the next uri. When the current song ends it will be played automatically and a STREAM_START message is send to the bus.
|
||||||
// When the next uri is not playable an error message is send when the pipeline goes to PLAY (or PAUSE) state or immediately if it is currently in PLAY state.
|
// When the next uri is not playable an error message is send when the pipeline goes to PLAY (or PAUSE) state or immediately if it is currently in PLAY state.
|
||||||
instance->next_uri_set_ = true;
|
instance->next_uri_set_ = true;
|
||||||
g_object_set(G_OBJECT(instance->pipeline_), "uri", instance->next_url_.constData(), nullptr);
|
g_object_set(G_OBJECT(instance->pipeline_), "uri", instance->next_media_url_.constData(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1057,9 +1082,10 @@ void GstEnginePipeline::RemoveAllBufferConsumers() {
|
|||||||
buffer_consumers_.clear();
|
buffer_consumers_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::SetNextUrl(const QByteArray &url, qint64 beginning_nanosec, qint64 end_nanosec) {
|
void GstEnginePipeline::SetNextUrl(const QByteArray &media_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
next_url_ = url;
|
next_media_url_ = media_url;
|
||||||
|
next_original_url_ = original_url;
|
||||||
next_beginning_offset_nanosec_ = beginning_nanosec;
|
next_beginning_offset_nanosec_ = beginning_nanosec;
|
||||||
next_end_offset_nanosec_ = end_nanosec;
|
next_end_offset_nanosec_ = end_nanosec;
|
||||||
|
|
||||||
|
|||||||
@@ -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 2018, 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
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
|
|
||||||
class GstEngine;
|
class GstEngine;
|
||||||
@@ -70,7 +72,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
void set_mono_playback(bool enabled);
|
void set_mono_playback(bool enabled);
|
||||||
|
|
||||||
// Creates the pipeline, returns false on error
|
// Creates the pipeline, returns false on error
|
||||||
bool InitFromUrl(const QByteArray &url, qint64 end_nanosec);
|
bool InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec);
|
||||||
bool InitFromString(const QString &pipeline);
|
bool InitFromString(const QString &pipeline);
|
||||||
|
|
||||||
// GstBufferConsumers get fed audio data. Thread-safe.
|
// GstBufferConsumers get fed audio data. Thread-safe.
|
||||||
@@ -88,13 +90,14 @@ class GstEnginePipeline : public QObject {
|
|||||||
void StartFader(qint64 duration_nanosec, QTimeLine::Direction direction = QTimeLine::Forward, QTimeLine::CurveShape shape = QTimeLine::LinearCurve, bool use_fudge_timer = true);
|
void StartFader(qint64 duration_nanosec, QTimeLine::Direction direction = QTimeLine::Forward, QTimeLine::CurveShape shape = QTimeLine::LinearCurve, bool use_fudge_timer = true);
|
||||||
|
|
||||||
// If this is set then it will be loaded automatically when playback finishes for gapless playback
|
// If this is set then it will be loaded automatically when playback finishes for gapless playback
|
||||||
void SetNextUrl(const QByteArray &url, qint64 beginning_nanosec, qint64 end_nanosec);
|
void SetNextUrl(const QByteArray &media_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool has_next_valid_url() const { return !next_url_.isNull() && !next_url_.isEmpty(); }
|
bool has_next_valid_url() const { return !next_media_url_.isNull() && !next_media_url_.isEmpty(); }
|
||||||
|
|
||||||
void SetSourceDevice(QString device) { source_device_ = device; }
|
void SetSourceDevice(QString device) { source_device_ = device; }
|
||||||
|
|
||||||
// Get information about the music playback
|
// Get information about the music playback
|
||||||
QByteArray url() const { return url_; }
|
QByteArray media_url() const { return media_url_; }
|
||||||
|
QUrl original_url() const { return original_url_; }
|
||||||
bool is_valid() const { return valid_; }
|
bool is_valid() const { return valid_; }
|
||||||
// Please note that this method (unlike GstEngine's.position()) is multiple-section media unaware.
|
// Please note that this method (unlike GstEngine's.position()) is multiple-section media unaware.
|
||||||
qint64 position() const;
|
qint64 position() const;
|
||||||
@@ -149,7 +152,8 @@ signals:
|
|||||||
void StreamStatusMessageReceived(GstMessage*);
|
void StreamStatusMessageReceived(GstMessage*);
|
||||||
void StreamStartMessageReceived();
|
void StreamStartMessageReceived();
|
||||||
|
|
||||||
QString ParseTag(GstTagList *list, const char *tag) const;
|
QString ParseStrTag(GstTagList *list, const char *tag) const;
|
||||||
|
guint ParseUIntTag(GstTagList *list, const char *tag) const;
|
||||||
|
|
||||||
bool InitDecodeBin(GstElement* new_bin);
|
bool InitDecodeBin(GstElement* new_bin);
|
||||||
bool InitAudioBin();
|
bool InitAudioBin();
|
||||||
@@ -212,8 +216,10 @@ signals:
|
|||||||
bool segment_start_received_;
|
bool segment_start_received_;
|
||||||
|
|
||||||
// The URL that is currently playing, and the URL that is to be preloaded when the current track is close to finishing.
|
// The URL that is currently playing, and the URL that is to be preloaded when the current track is close to finishing.
|
||||||
QByteArray url_;
|
QByteArray media_url_;
|
||||||
QByteArray next_url_;
|
QUrl original_url_;
|
||||||
|
QByteArray next_media_url_;
|
||||||
|
QUrl next_original_url_;
|
||||||
|
|
||||||
// If this is > 0 then the pipeline will be forced to stop when playback goes past this position.
|
// If this is > 0 then the pipeline will be forced to stop when playback goes past this position.
|
||||||
qint64 end_offset_nanosec_;
|
qint64 end_offset_nanosec_;
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ bool PhononEngine::CanDecode(const QUrl &url) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhononEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool PhononEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
media_object_->setCurrentSource(Phonon::MediaSource(url));
|
media_object_->setCurrentSource(Phonon::MediaSource(media_url));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,3 +189,7 @@ bool PhononEngine::ValidOutput(const QString &output) {
|
|||||||
bool PhononEngine::CustomDeviceSupport(const QString &output) {
|
bool PhononEngine::CustomDeviceSupport(const QString &output) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhononEngine::ALSADeviceSupport(const QString &output) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class PhononEngine : public Engine::Base {
|
|||||||
|
|
||||||
bool CanDecode(const QUrl &url);
|
bool CanDecode(const QUrl &url);
|
||||||
|
|
||||||
bool Load(const QUrl &, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool Play(quint64 offset_nanosec);
|
bool Play(quint64 offset_nanosec);
|
||||||
void Stop(bool stop_after = false);
|
void Stop(bool stop_after = false);
|
||||||
void Pause();
|
void Pause();
|
||||||
@@ -66,6 +66,7 @@ class PhononEngine : public Engine::Base {
|
|||||||
QString DefaultOutput() { return ""; }
|
QString DefaultOutput() { return ""; }
|
||||||
bool ValidOutput(const QString &output);
|
bool ValidOutput(const QString &output);
|
||||||
bool CustomDeviceSupport(const QString &output);
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
bool ALSADeviceSupport(const QString &output);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetVolumeSW( uint percent );
|
void SetVolumeSW( uint percent );
|
||||||
|
|||||||
@@ -100,12 +100,12 @@ bool VLCEngine::Initialised() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VLCEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool VLCEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
if (!Initialised()) return false;
|
if (!Initialised()) return false;
|
||||||
|
|
||||||
// Create the media object
|
// Create the media object
|
||||||
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, url.toEncoded().constData()));
|
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, media_url.toEncoded().constData()));
|
||||||
|
|
||||||
libvlc_media_player_set_media(player_, media);
|
libvlc_media_player_set_media(player_, media);
|
||||||
|
|
||||||
@@ -238,6 +238,10 @@ bool VLCEngine::CustomDeviceSupport(const QString &output) {
|
|||||||
return (output == "auto" ? false : true);
|
return (output == "auto" ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VLCEngine::ALSADeviceSupport(const QString &output) {
|
||||||
|
return (output == "alsa");
|
||||||
|
}
|
||||||
|
|
||||||
uint VLCEngine::position() const {
|
uint VLCEngine::position() const {
|
||||||
|
|
||||||
if (!Initialised()) return (0);
|
if (!Initialised()) return (0);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class VLCEngine : public Engine::Base {
|
|||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
Engine::State state() const { return state_; }
|
Engine::State state() const { return state_; }
|
||||||
bool Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool Play(quint64 offset_nanosec);
|
bool Play(quint64 offset_nanosec);
|
||||||
void Stop(bool stop_after = false);
|
void Stop(bool stop_after = false);
|
||||||
void Pause();
|
void Pause();
|
||||||
@@ -64,6 +64,7 @@ class VLCEngine : public Engine::Base {
|
|||||||
bool ValidOutput(const QString &output);
|
bool ValidOutput(const QString &output);
|
||||||
QString DefaultOutput() { return ""; }
|
QString DefaultOutput() { return ""; }
|
||||||
bool CustomDeviceSupport(const QString &output);
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
bool ALSADeviceSupport(const QString &output);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
libvlc_instance_t *instance_;
|
libvlc_instance_t *instance_;
|
||||||
|
|||||||
@@ -180,20 +180,20 @@ Engine::State XineEngine::state() const {
|
|||||||
return Engine::Empty;
|
return Engine::Empty;
|
||||||
case XINE_STATUS_STOP:
|
case XINE_STATUS_STOP:
|
||||||
default:
|
default:
|
||||||
return url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XineEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool XineEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
|
||||||
if (!EnsureStream()) return false;
|
if (!EnsureStream()) return false;
|
||||||
|
|
||||||
Engine::Base::Load(url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||||
|
|
||||||
xine_close(stream_);
|
xine_close(stream_);
|
||||||
|
|
||||||
//int result = xine_open(stream_, url.path().toUtf8());
|
//int result = xine_open(stream_, url.path().toUtf8());
|
||||||
int result = xine_open(stream_, url.toString().toUtf8());
|
int result = xine_open(stream_, media_url.toString().toUtf8());
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
||||||
#ifndef XINE_SAFE_MODE
|
#ifndef XINE_SAFE_MODE
|
||||||
@@ -345,6 +345,10 @@ bool XineEngine::CustomDeviceSupport(const QString &output) {
|
|||||||
return (output == "alsa" || output == "oss" || output == "jack" || output == "pulseaudio");
|
return (output == "alsa" || output == "oss" || output == "jack" || output == "pulseaudio");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool XineEngine::ALSADeviceSupport(const QString &output) {
|
||||||
|
return (output == "alsa");
|
||||||
|
}
|
||||||
|
|
||||||
void XineEngine::ReloadSettings() {
|
void XineEngine::ReloadSettings() {
|
||||||
|
|
||||||
Engine::Base::ReloadSettings();
|
Engine::Base::ReloadSettings();
|
||||||
@@ -371,7 +375,7 @@ uint XineEngine::length() const {
|
|||||||
|
|
||||||
// Xine often delivers nonsense values for VBR files and such, so we only use the length for remote files
|
// Xine often delivers nonsense values for VBR files and such, so we only use the length for remote files
|
||||||
|
|
||||||
if (url_.scheme().toLower() == "file") return 0;
|
if (media_url_.scheme().toLower() == "file") return 0;
|
||||||
else {
|
else {
|
||||||
int pos = 0, time = 0, length = 0;
|
int pos = 0, time = 0, length = 0;
|
||||||
|
|
||||||
@@ -473,10 +477,9 @@ bool XineEngine::MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b) {
|
|||||||
b.artist = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ARTIST));
|
b.artist = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ARTIST));
|
||||||
b.album = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ALBUM));
|
b.album = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ALBUM));
|
||||||
b.genre = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_GENRE));
|
b.genre = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_GENRE));
|
||||||
b.year = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_YEAR));
|
b.year = atoi(xine_get_meta_info(tmpstream, XINE_META_INFO_YEAR));
|
||||||
b.tracknr = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_TRACK_NUMBER));
|
b.tracknr = atoi(xine_get_meta_info(tmpstream, XINE_META_INFO_TRACK_NUMBER));
|
||||||
if (b.tracknr.isEmpty())
|
//if (b.tracknr <= 0) b.tracknr = QFileInfo(url.path()).fileName();
|
||||||
b.tracknr = QFileInfo(url.path()).fileName();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b.title = QString("Track %1").arg(QFileInfo(url.path()).fileName());
|
b.title = QString("Track %1").arg(QFileInfo(url.path()).fileName());
|
||||||
@@ -486,18 +489,19 @@ bool XineEngine::MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b) {
|
|||||||
|
|
||||||
if (audioCodec == "CDDA" || audioCodec == "WAV") {
|
if (audioCodec == "CDDA" || audioCodec == "WAV") {
|
||||||
result = true;
|
result = true;
|
||||||
|
b.url = url;
|
||||||
int samplerate = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
|
int samplerate = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
|
||||||
|
int bitdepth = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_BITS);
|
||||||
|
int channels = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_CHANNELS);
|
||||||
// Xine would provide a XINE_STREAM_INFO_AUDIO_BITRATE, but unfortunately not for CDDA or WAV so we calculate the bitrate by our own
|
// Xine would provide a XINE_STREAM_INFO_AUDIO_BITRATE, but unfortunately not for CDDA or WAV so we calculate the bitrate by our own
|
||||||
int bitsPerSample = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_BITS);
|
int bitrate = (samplerate * bitdepth * channels) / 1000;
|
||||||
int nbrChannels = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_CHANNELS);
|
|
||||||
int bitrate = (samplerate * bitsPerSample * nbrChannels) / 1000;
|
|
||||||
|
|
||||||
b.bitrate = QString::number(bitrate);
|
b.samplerate = samplerate;
|
||||||
b.samplerate = QString::number(samplerate);
|
b.bitdepth = bitdepth;
|
||||||
|
b.bitrate = bitrate;
|
||||||
int pos, time, length = 0;
|
int pos, time, length = 0;
|
||||||
xine_get_pos_length(tmpstream, &pos, &time, &length);
|
xine_get_pos_length(tmpstream, &pos, &time, &length);
|
||||||
b.length = QString::number(length / 1000);
|
b.length = length / 1000;
|
||||||
}
|
}
|
||||||
xine_close(tmpstream);
|
xine_close(tmpstream);
|
||||||
}
|
}
|
||||||
@@ -746,7 +750,7 @@ bool XineEngine::event(QEvent *e) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case XineEvent::InfoMessage:
|
case XineEvent::InfoMessage:
|
||||||
emit InfoMessage((*message).arg(url_.toString()));
|
emit InfoMessage((*message).arg(media_url_.toString()));
|
||||||
delete message;
|
delete message;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -767,7 +771,7 @@ bool XineEngine::event(QEvent *e) {
|
|||||||
|
|
||||||
case XineEvent::Redirecting:
|
case XineEvent::Redirecting:
|
||||||
emit StatusText(QString("Redirecting to: ").arg(*message));
|
emit StatusText(QString("Redirecting to: ").arg(*message));
|
||||||
Load(QUrl(*message), Engine::Auto, false, 0, 0);
|
Load(QUrl(*message), original_url_, Engine::Auto, false, 0, 0);
|
||||||
Play(0);
|
Play(0);
|
||||||
delete message;
|
delete message;
|
||||||
return true;
|
return true;
|
||||||
@@ -783,15 +787,18 @@ bool XineEngine::event(QEvent *e) {
|
|||||||
Engine::SimpleMetaBundle XineEngine::fetchMetaData() const {
|
Engine::SimpleMetaBundle XineEngine::fetchMetaData() const {
|
||||||
|
|
||||||
Engine::SimpleMetaBundle bundle;
|
Engine::SimpleMetaBundle bundle;
|
||||||
|
bundle.url = original_url_;
|
||||||
bundle.title = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_TITLE));
|
bundle.title = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_TITLE));
|
||||||
bundle.artist = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ARTIST));
|
bundle.artist = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ARTIST));
|
||||||
bundle.album = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ALBUM));
|
bundle.album = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ALBUM));
|
||||||
bundle.comment = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_COMMENT));
|
bundle.comment = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_COMMENT));
|
||||||
bundle.genre = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_GENRE));
|
bundle.genre = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_GENRE));
|
||||||
bundle.bitrate = QString::number(xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITRATE) / 1000);
|
bundle.length = 0;
|
||||||
bundle.samplerate = QString::number(xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_SAMPLERATE));
|
bundle.year = atoi(xine_get_meta_info(stream_, XINE_META_INFO_YEAR));
|
||||||
bundle.year = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_YEAR));
|
bundle.tracknr = atoi(xine_get_meta_info(stream_, XINE_META_INFO_TRACK_NUMBER));
|
||||||
bundle.tracknr = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_TRACK_NUMBER));
|
bundle.samplerate = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
|
||||||
|
bundle.bitdepth = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITS);
|
||||||
|
bundle.bitrate = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITRATE) / 1000;
|
||||||
|
|
||||||
return bundle;
|
return bundle;
|
||||||
|
|
||||||
@@ -895,7 +902,7 @@ void XineEngine::DetermineAndShowErrorMessage() {
|
|||||||
// xine can read the plugin but it didn't find any codec
|
// xine can read the plugin but it didn't find any codec
|
||||||
// THUS xine=daft for telling us it could handle the format in canDecode!
|
// THUS xine=daft for telling us it could handle the format in canDecode!
|
||||||
body = "There is no available decoder.";
|
body = "There is no available decoder.";
|
||||||
QString const ext = QFileInfo(url_.path()).completeSuffix();
|
QString const ext = QFileInfo(media_url_.path()).completeSuffix();
|
||||||
// TODO:
|
// TODO:
|
||||||
// if (ext == "mp3" && EngineController::installDistroCodec("xine-engine"))
|
// if (ext == "mp3" && EngineController::installDistroCodec("xine-engine"))
|
||||||
// return;
|
// return;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class XineEngine : public Engine::Base {
|
|||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
Engine::State state() const;
|
Engine::State state() const;
|
||||||
bool Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||||
bool Play(quint64 offset_nanosec);
|
bool Play(quint64 offset_nanosec);
|
||||||
void Stop(bool stop_after = false);
|
void Stop(bool stop_after = false);
|
||||||
void Pause();
|
void Pause();
|
||||||
@@ -87,6 +87,7 @@ class XineEngine : public Engine::Base {
|
|||||||
bool ValidOutput(const QString &output);
|
bool ValidOutput(const QString &output);
|
||||||
QString DefaultOutput() { return "auto"; }
|
QString DefaultOutput() { return "auto"; }
|
||||||
bool CustomDeviceSupport(const QString &output);
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
bool ALSADeviceSupport(const QString &output);
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
@@ -115,7 +116,8 @@ class XineEngine : public Engine::Base {
|
|||||||
float preamp_;
|
float preamp_;
|
||||||
std::unique_ptr<PruneScopeThread> prune_;
|
std::unique_ptr<PruneScopeThread> prune_;
|
||||||
|
|
||||||
QUrl url_;
|
QUrl media_url_;
|
||||||
|
QUrl original_url_;
|
||||||
|
|
||||||
static int last_error_;
|
static int last_error_;
|
||||||
static time_t last_error_time_;
|
static time_t last_error_time_;
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ class InternetModel : public QStandardItemModel {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T *Service() {
|
static T *Service() {
|
||||||
//return static_cast<T*>(ServiceByName(T::kServiceName));
|
|
||||||
return static_cast<T*>(ServiceBySource(T::kSource));
|
return static_cast<T*>(ServiceBySource(T::kSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@
|
|||||||
#include "internetmodel.h"
|
#include "internetmodel.h"
|
||||||
#include "internetservice.h"
|
#include "internetservice.h"
|
||||||
|
|
||||||
InternetService::InternetService(Song::Source source, const QString &name, Application *app, InternetModel *model, QObject *parent)
|
InternetService::InternetService(Song::Source source, const QString &name, const QString &url_scheme, Application *app, InternetModel *model, QObject *parent)
|
||||||
: QObject(parent), app_(app), model_(model), source_(source), name_(name) {
|
: QObject(parent), app_(app), model_(model), source_(source), name_(name), url_scheme_(url_scheme) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,11 @@ class InternetService : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InternetService(Song::Source source, const QString &name, Application *app, InternetModel *model, QObject *parent = nullptr);
|
InternetService(Song::Source source, const QString &name, const QString &url_scheme, Application *app, InternetModel *model, QObject *parent = nullptr);
|
||||||
virtual ~InternetService() {}
|
virtual ~InternetService() {}
|
||||||
Song::Source source() const { return source_; }
|
Song::Source source() const { return source_; }
|
||||||
QString name() const { return name_; }
|
QString name() const { return name_; }
|
||||||
|
QString url_scheme() const { return url_scheme_; }
|
||||||
InternetModel *model() const { return model_; }
|
InternetModel *model() const { return model_; }
|
||||||
virtual bool has_initial_load_settings() const { return false; }
|
virtual bool has_initial_load_settings() const { return false; }
|
||||||
virtual void InitialLoadSettings() {}
|
virtual void InitialLoadSettings() {}
|
||||||
@@ -61,6 +62,7 @@ class InternetService : public QObject {
|
|||||||
InternetModel *model_;
|
InternetModel *model_;
|
||||||
Song::Source source_;
|
Song::Source source_;
|
||||||
QString name_;
|
QString name_;
|
||||||
|
QString url_scheme_;
|
||||||
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(InternetService*);
|
Q_DECLARE_METATYPE(InternetService*);
|
||||||
|
|||||||
@@ -1129,7 +1129,7 @@ bool Playlist::ComparePathDepths(Qt::SortOrder order, shared_ptr<PlaylistItem> _
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString Playlist::column_name(Column column) {
|
QString Playlist::column_name(Column column) {
|
||||||
|
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case Column_Title: return tr("Title");
|
case Column_Title: return tr("Title");
|
||||||
case Column_Artist: return tr("Artist");
|
case Column_Artist: return tr("Artist");
|
||||||
@@ -1456,14 +1456,18 @@ void Playlist::StopAfter(int row) {
|
|||||||
|
|
||||||
void Playlist::SetStreamMetadata(const QUrl &url, const Song &song) {
|
void Playlist::SetStreamMetadata(const QUrl &url, const Song &song) {
|
||||||
|
|
||||||
//qLog(Debug) << "Setting metadata for" << url << "to" << song.artist() << song.title();
|
|
||||||
|
|
||||||
if (!current_item()) return;
|
if (!current_item()) return;
|
||||||
|
|
||||||
if (current_item()->Url() != url) return;
|
if (current_item()->Url() != url) return;
|
||||||
|
|
||||||
// Don't update the metadata if it's only a minor change from before
|
// Don't update the metadata if it's only a minor change from before
|
||||||
if (current_item()->Metadata().artist() == song.artist() && current_item()->Metadata().title() == song.title()) return;
|
if (current_item()->Metadata().artist() == song.artist() && current_item()->Metadata().title() == song.title() && current_item()->Metadata().album() == song.album()) return;
|
||||||
|
|
||||||
|
// TODO: Update context & playlist if changed, but don't show popup.
|
||||||
|
//(song.bitrate() <= 0 || current_item()->Metadata().bitrate() == song.bitrate())
|
||||||
|
//(song.samplerate() <= 0 || current_item()->Metadata().samplerate() == song.samplerate())
|
||||||
|
//(song.bitdepth() <= 0 || current_item()->Metadata().bitdepth() == song.bitdepth())
|
||||||
|
|
||||||
|
qLog(Debug) << "Setting metadata for" << url << "to" << song.artist() << song.title();
|
||||||
|
|
||||||
current_item()->SetTemporaryMetadata(song);
|
current_item()->SetTemporaryMetadata(song);
|
||||||
|
|
||||||
@@ -1762,7 +1766,7 @@ void Playlist::ItemChanged(PlaylistItemPtr item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::InformOfCurrentSongChange() {
|
void Playlist::InformOfCurrentSongChange() {
|
||||||
|
|
||||||
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
|
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
|
||||||
|
|
||||||
// if the song is invalid, we won't play it - there's no point in informing anybody about the change
|
// if the song is invalid, we won't play it - there's no point in informing anybody about the change
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ void PlaylistDelegateBase::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
QStyleOptionViewItem PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
||||||
|
|
||||||
if (!view_) return option;
|
if (!view_) return option;
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem
|
|||||||
if (view_->header()->logicalIndexAt(top_left) != index.column())
|
if (view_->header()->logicalIndexAt(top_left) != index.column())
|
||||||
return option;
|
return option;
|
||||||
|
|
||||||
QStyleOptionViewItemV4 ret(option);
|
QStyleOptionViewItem ret(option);
|
||||||
|
|
||||||
if (index.data(Playlist::Role_IsCurrent).toBool()) {
|
if (index.data(Playlist::Role_IsCurrent).toBool()) {
|
||||||
// Move the text in a bit on the first column for the song that's currently playing
|
// Move the text in a bit on the first column for the song that's currently playing
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class PlaylistDelegateBase : public QueuedItemDelegate {
|
|||||||
QString displayText(const QVariant &value, const QLocale &locale) const;
|
QString displayText(const QVariant &value, const QLocale &locale) const;
|
||||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
|
||||||
QStyleOptionViewItemV4 Adjusted(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
QStyleOptionViewItem Adjusted(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
|
||||||
static const int kMinHeight;
|
static const int kMinHeight;
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,7 @@
|
|||||||
|
|
||||||
#include "internet/internetplaylistitem.h"
|
#include "internet/internetplaylistitem.h"
|
||||||
|
|
||||||
PlaylistItem::~PlaylistItem() {
|
PlaylistItem::~PlaylistItem() {}
|
||||||
}
|
|
||||||
|
|
||||||
PlaylistItem *PlaylistItem::NewFromSource(const Song::Source &source) {
|
PlaylistItem *PlaylistItem::NewFromSource(const Song::Source &source) {
|
||||||
|
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ void PlaylistView::drawTree(QPainter *painter, const QRegion ®ion) const {
|
|||||||
|
|
||||||
void PlaylistView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
void PlaylistView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
||||||
|
|
||||||
QStyleOptionViewItemV4 opt(option);
|
QStyleOptionViewItem opt(option);
|
||||||
|
|
||||||
bool is_current = index.data(Playlist::Role_IsCurrent).toBool();
|
bool is_current = index.data(Playlist::Role_IsCurrent).toBool();
|
||||||
bool is_paused = index.data(Playlist::Role_IsPaused).toBool();
|
bool is_paused = index.data(Playlist::Role_IsPaused).toBool();
|
||||||
@@ -452,7 +452,7 @@ void PlaylistView::drawRow(QPainter *painter, const QStyleOptionViewItem &option
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistView::UpdateCachedCurrentRowPixmap(QStyleOptionViewItemV4 option, const QModelIndex &index) {
|
void PlaylistView::UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex &index) {
|
||||||
|
|
||||||
cached_current_row_rect_ = option.rect;
|
cached_current_row_rect_ = option.rect;
|
||||||
cached_current_row_row_ = index.row();
|
cached_current_row_row_ = index.row();
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class PlaylistView : public QTreeView {
|
|||||||
private:
|
private:
|
||||||
void ReloadBarPixmaps();
|
void ReloadBarPixmaps();
|
||||||
QList<QPixmap> LoadBarPixmap(const QString &filename);
|
QList<QPixmap> LoadBarPixmap(const QString &filename);
|
||||||
void UpdateCachedCurrentRowPixmap(QStyleOptionViewItemV4 option, const QModelIndex &index);
|
void UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex &index);
|
||||||
|
|
||||||
void set_background_image_type(BackgroundImageType bg) {
|
void set_background_image_type(BackgroundImageType bg) {
|
||||||
background_image_type_ = bg;
|
background_image_type_ = bg;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QListView>
|
||||||
|
|
||||||
#include "backendsettingspage.h"
|
#include "backendsettingspage.h"
|
||||||
|
|
||||||
@@ -112,6 +113,19 @@ void BackendSettingsPage::Load() {
|
|||||||
ui_->stickslider_replaygainpreamp->setValue(s_.value("rgpreamp", 0.0).toDouble() * 10 + 150);
|
ui_->stickslider_replaygainpreamp->setValue(s_.value("rgpreamp", 0.0).toDouble() * 10 + 150);
|
||||||
ui_->checkbox_replaygaincompression->setChecked(s_.value("rgcompression", true).toBool());
|
ui_->checkbox_replaygaincompression->setChecked(s_.value("rgcompression", true).toBool());
|
||||||
|
|
||||||
|
int alsaplug_int = alsa_plugin(s_.value("alsaplugin", 0).toInt());
|
||||||
|
if (alsa_plugin(alsaplug_int)) {
|
||||||
|
alsa_plugin alsaplugin = alsa_plugin(alsaplug_int);
|
||||||
|
switch (alsaplugin) {
|
||||||
|
case alsa_plugin::alsa_hw:
|
||||||
|
ui_->radiobutton_alsa_hw->setChecked(true);
|
||||||
|
break;
|
||||||
|
case alsa_plugin::alsa_plughw:
|
||||||
|
ui_->radiobutton_alsa_plughw->setChecked(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!EngineInitialised()) return;
|
if (!EngineInitialised()) return;
|
||||||
|
|
||||||
if (engine()->state() == Engine::Empty) {
|
if (engine()->state() == Engine::Empty) {
|
||||||
@@ -139,6 +153,8 @@ void BackendSettingsPage::ConnectSignals() {
|
|||||||
connect(ui_->lineedit_device, SIGNAL(textChanged(const QString &)), SLOT(DeviceStringChanged()));
|
connect(ui_->lineedit_device, SIGNAL(textChanged(const QString &)), SLOT(DeviceStringChanged()));
|
||||||
connect(ui_->slider_bufferminfill, SIGNAL(valueChanged(int)), SLOT(BufferMinFillChanged(int)));
|
connect(ui_->slider_bufferminfill, SIGNAL(valueChanged(int)), SLOT(BufferMinFillChanged(int)));
|
||||||
connect(ui_->stickslider_replaygainpreamp, SIGNAL(valueChanged(int)), SLOT(RgPreampChanged(int)));
|
connect(ui_->stickslider_replaygainpreamp, SIGNAL(valueChanged(int)), SLOT(RgPreampChanged(int)));
|
||||||
|
connect(ui_->radiobutton_alsa_hw, SIGNAL(clicked(bool)), SLOT(radiobutton_alsa_hw_clicked(bool)));
|
||||||
|
connect(ui_->radiobutton_alsa_plughw, SIGNAL(clicked(bool)), SLOT(radiobutton_alsa_plughw_clicked(bool)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,6 +287,27 @@ void BackendSettingsPage::Load_Device(QString output, QVariant device) {
|
|||||||
ui_->lineedit_device->setEnabled(false);
|
ui_->lineedit_device->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (engine()->ALSADeviceSupport(output)) {
|
||||||
|
ui_->radiobutton_alsa_hw->setEnabled(true);
|
||||||
|
ui_->radiobutton_alsa_plughw->setEnabled(true);
|
||||||
|
if (device.toString().contains(QRegExp("^plughw:.*"))) {
|
||||||
|
ui_->radiobutton_alsa_hw->setChecked(false);
|
||||||
|
ui_->radiobutton_alsa_plughw->setChecked(true);
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_plughw);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ui_->radiobutton_alsa_plughw->setChecked(false);
|
||||||
|
ui_->radiobutton_alsa_hw->setChecked(true);
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_hw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ui_->radiobutton_alsa_hw->setEnabled(false);
|
||||||
|
ui_->radiobutton_alsa_hw->setChecked(false);
|
||||||
|
ui_->radiobutton_alsa_plughw->setEnabled(false);
|
||||||
|
ui_->radiobutton_alsa_plughw->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
bool found(false);
|
bool found(false);
|
||||||
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
QVariant d = ui_->combobox_device->itemData(i).value<QVariant>();
|
QVariant d = ui_->combobox_device->itemData(i).value<QVariant>();
|
||||||
@@ -285,17 +322,12 @@ void BackendSettingsPage::Load_Device(QString output, QVariant device) {
|
|||||||
if (engine()->CustomDeviceSupport(output) && device.type() == QVariant::String && !device.toString().isEmpty()) {
|
if (engine()->CustomDeviceSupport(output) && device.type() == QVariant::String && !device.toString().isEmpty()) {
|
||||||
ui_->lineedit_device->setText(device.toString());
|
ui_->lineedit_device->setText(device.toString());
|
||||||
if (!found) {
|
if (!found) {
|
||||||
bool have_custom(false);
|
|
||||||
int index_custom = 0;
|
|
||||||
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
if (ui_->combobox_device->itemText(i) == "Custom") {
|
if (ui_->combobox_device->itemText(i) == "Custom") {
|
||||||
have_custom = true;
|
|
||||||
index_custom = i;
|
|
||||||
if (ui_->combobox_device->currentText() != "Custom") ui_->combobox_device->setCurrentIndex(i);
|
if (ui_->combobox_device->currentText() != "Custom") ui_->combobox_device->setCurrentIndex(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (have_custom) ui_->combobox_device->setItemData(index_custom, QVariant(device.toString()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +347,9 @@ void BackendSettingsPage::Save() {
|
|||||||
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
||||||
output_name = output.name;
|
output_name = output.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui_->combobox_device->currentText().isEmpty()) device_value = QVariant();
|
if (ui_->combobox_device->currentText().isEmpty()) device_value = QVariant();
|
||||||
|
else if (ui_->combobox_device->currentText() == "Custom") device_value = ui_->lineedit_device->text();
|
||||||
else device_value = ui_->combobox_device->itemData(ui_->combobox_device->currentIndex()).value<QVariant>();
|
else device_value = ui_->combobox_device->itemData(ui_->combobox_device->currentIndex()).value<QVariant>();
|
||||||
|
|
||||||
s_.setValue("engine", EngineName(enginetype));
|
s_.setValue("engine", EngineName(enginetype));
|
||||||
@@ -330,6 +364,10 @@ void BackendSettingsPage::Save() {
|
|||||||
s_.setValue("rgpreamp", float(ui_->stickslider_replaygainpreamp->value()) / 10 - 15);
|
s_.setValue("rgpreamp", float(ui_->stickslider_replaygainpreamp->value()) / 10 - 15);
|
||||||
s_.setValue("rgcompression", ui_->checkbox_replaygaincompression->isChecked());
|
s_.setValue("rgcompression", ui_->checkbox_replaygaincompression->isChecked());
|
||||||
|
|
||||||
|
if (ui_->radiobutton_alsa_hw->isChecked()) s_.setValue("alsaplugin", static_cast<int>(alsa_plugin::alsa_hw));
|
||||||
|
else if (ui_->radiobutton_alsa_plughw->isChecked()) s_.setValue("alsaplugin", static_cast<int>(alsa_plugin::alsa_plughw));
|
||||||
|
else s_.remove("alsaplugin");
|
||||||
|
|
||||||
// If engine has not been changed, but output or device has been changed,
|
// If engine has not been changed, but output or device has been changed,
|
||||||
// then set_output_changed(true) to reinitialize engine when dialog closes.
|
// then set_output_changed(true) to reinitialize engine when dialog closes.
|
||||||
if (enginetype == enginetype_current_ && (output_name != output_current_ || device_value != device_current_)) dialog()->set_output_changed(true);
|
if (enginetype == enginetype_current_ && (output_name != output_current_ || device_value != device_current_)) dialog()->set_output_changed(true);
|
||||||
@@ -347,7 +385,7 @@ void BackendSettingsPage::Cancel() {
|
|||||||
void BackendSettingsPage::EngineChanged(int index) {
|
void BackendSettingsPage::EngineChanged(int index) {
|
||||||
|
|
||||||
if (!configloaded_ || !EngineInitialised()) return;
|
if (!configloaded_ || !EngineInitialised()) return;
|
||||||
|
|
||||||
QVariant v = ui_->combobox_engine->itemData(index);
|
QVariant v = ui_->combobox_engine->itemData(index);
|
||||||
Engine::EngineType enginetype = v.value<Engine::EngineType>();
|
Engine::EngineType enginetype = v.value<Engine::EngineType>();
|
||||||
|
|
||||||
@@ -386,12 +424,7 @@ void BackendSettingsPage::DeviceSelectionChanged(int index) {
|
|||||||
|
|
||||||
if (engine()->CustomDeviceSupport(output.name)) {
|
if (engine()->CustomDeviceSupport(output.name)) {
|
||||||
ui_->lineedit_device->setEnabled(true);
|
ui_->lineedit_device->setEnabled(true);
|
||||||
if (ui_->combobox_device->currentText() == "Custom") {
|
if (ui_->combobox_device->currentText() != "Custom" && device.type() == QVariant::String) ui_->lineedit_device->setText(device.toString());
|
||||||
ui_->combobox_device->setItemData(index, QVariant(ui_->lineedit_device->text()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (device.type() == QVariant::String) ui_->lineedit_device->setText(device.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->lineedit_device->setEnabled(false);
|
ui_->lineedit_device->setEnabled(false);
|
||||||
@@ -409,10 +442,22 @@ void BackendSettingsPage::DeviceStringChanged() {
|
|||||||
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
||||||
bool found(false);
|
bool found(false);
|
||||||
|
|
||||||
|
if (engine()->ALSADeviceSupport(output.name)) {
|
||||||
|
if (ui_->lineedit_device->text().contains(QRegExp("^hw:.*")) && !ui_->radiobutton_alsa_hw->isChecked()) {
|
||||||
|
ui_->radiobutton_alsa_hw->setChecked(true);
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_hw);
|
||||||
|
}
|
||||||
|
else if (ui_->lineedit_device->text().contains(QRegExp("^plughw:.*")) && !ui_->radiobutton_alsa_plughw->isChecked()) {
|
||||||
|
ui_->radiobutton_alsa_plughw->setChecked(true);
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_plughw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
QVariant device = ui_->combobox_device->itemData(i).value<QVariant>();
|
QVariant device = ui_->combobox_device->itemData(i).value<QVariant>();
|
||||||
if (device.type() != QVariant::String) continue;
|
if (device.type() != QVariant::String) continue;
|
||||||
if (device.toString().isEmpty()) continue;
|
if (device.toString().isEmpty()) continue;
|
||||||
|
if (ui_->combobox_device->itemText(i) == "Custom") continue;
|
||||||
if (device.toString() == ui_->lineedit_device->text()) {
|
if (device.toString() == ui_->lineedit_device->text()) {
|
||||||
if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i);
|
if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i);
|
||||||
found = true;
|
found = true;
|
||||||
@@ -430,7 +475,6 @@ void BackendSettingsPage::DeviceStringChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ui_->combobox_device->currentText() == "Custom") {
|
if (ui_->combobox_device->currentText() == "Custom") {
|
||||||
ui_->combobox_device->setItemData(ui_->combobox_device->currentIndex(), QVariant(ui_->lineedit_device->text()));
|
|
||||||
if ((ui_->lineedit_device->text().isEmpty()) && (ui_->combobox_device->count() > 0) && (ui_->combobox_device->currentIndex() != 0)) ui_->combobox_device->setCurrentIndex(0);
|
if ((ui_->lineedit_device->text().isEmpty()) && (ui_->combobox_device->count() > 0) && (ui_->combobox_device->currentIndex() != 0)) ui_->combobox_device->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,3 +546,73 @@ void BackendSettingsPage::XineWarning() {
|
|||||||
xinewarning_ = true;
|
xinewarning_ = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackendSettingsPage::SwitchALSADevices(alsa_plugin alsaplugin) {
|
||||||
|
|
||||||
|
// All ALSA devices are listed twice, one for "hw" and one for "plughw"
|
||||||
|
// Only show one of them by making the other ones invisible based on the alsa plugin radiobuttons
|
||||||
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
|
QListView *view = qobject_cast<QListView *>(ui_->combobox_device->view());
|
||||||
|
if (!view) continue;
|
||||||
|
if (alsaplugin == alsa_plugin::alsa_hw && ui_->combobox_device->itemData(i).toString().contains(QRegExp("^plughw:.*"))) {
|
||||||
|
view->setRowHidden(i, true);
|
||||||
|
}
|
||||||
|
else if (alsaplugin == alsa_plugin::alsa_plughw && ui_->combobox_device->itemData(i).toString().contains(QRegExp("^hw:.*"))) {
|
||||||
|
view->setRowHidden(i, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
view->setRowHidden(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendSettingsPage::radiobutton_alsa_hw_clicked(bool checked) {
|
||||||
|
|
||||||
|
if (!configloaded_ || !EngineInitialised()) return;
|
||||||
|
|
||||||
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
||||||
|
if (!engine()->ALSADeviceSupport(output.name)) return;
|
||||||
|
|
||||||
|
if (ui_->lineedit_device->text().contains(QRegExp("^plughw:.*"))) {
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_hw);
|
||||||
|
QString device_new = ui_->lineedit_device->text().replace(QRegExp("^plughw:"), "hw:");
|
||||||
|
bool found(false);
|
||||||
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
|
QVariant device = ui_->combobox_device->itemData(i).value<QVariant>();
|
||||||
|
if (device.type() != QVariant::String) continue;
|
||||||
|
if (device.toString().isEmpty()) continue;
|
||||||
|
if (device.toString() == device_new) {
|
||||||
|
if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) ui_->lineedit_device->setText(device_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendSettingsPage::radiobutton_alsa_plughw_clicked(bool checked) {
|
||||||
|
|
||||||
|
if (!configloaded_ || !EngineInitialised()) return;
|
||||||
|
|
||||||
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
||||||
|
if (!engine()->ALSADeviceSupport(output.name)) return;
|
||||||
|
|
||||||
|
if (ui_->lineedit_device->text().contains(QRegExp("^hw:.*"))) {
|
||||||
|
SwitchALSADevices(alsa_plugin::alsa_plughw);
|
||||||
|
QString device_new = ui_->lineedit_device->text().replace(QRegExp("^hw:"), "plughw:");
|
||||||
|
bool found(false);
|
||||||
|
for (int i = 0; i < ui_->combobox_device->count(); ++i) {
|
||||||
|
QVariant device = ui_->combobox_device->itemData(i).value<QVariant>();
|
||||||
|
if (device.type() != QVariant::String) continue;
|
||||||
|
if (device.toString().isEmpty()) continue;
|
||||||
|
if (device.toString() == device_new) {
|
||||||
|
if (ui_->combobox_device->currentIndex() != i) ui_->combobox_device->setCurrentIndex(i);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) ui_->lineedit_device->setText(device_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,8 +63,16 @@ public:
|
|||||||
void DeviceStringChanged();
|
void DeviceStringChanged();
|
||||||
void RgPreampChanged(int value);
|
void RgPreampChanged(int value);
|
||||||
void BufferMinFillChanged(int value);
|
void BufferMinFillChanged(int value);
|
||||||
|
void radiobutton_alsa_hw_clicked(bool checked);
|
||||||
|
void radiobutton_alsa_plughw_clicked(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
enum alsa_plugin {
|
||||||
|
alsa_hw = 1,
|
||||||
|
alsa_plughw = 2
|
||||||
|
};
|
||||||
|
|
||||||
Ui_BackendSettingsPage *ui_;
|
Ui_BackendSettingsPage *ui_;
|
||||||
|
|
||||||
void ConnectSignals();
|
void ConnectSignals();
|
||||||
@@ -78,6 +86,7 @@ private:
|
|||||||
void ShowWarning(QString text);
|
void ShowWarning(QString text);
|
||||||
void ResetWarning();
|
void ResetWarning();
|
||||||
void XineWarning();
|
void XineWarning();
|
||||||
|
void SwitchALSADevices(alsa_plugin alsaplugin);
|
||||||
|
|
||||||
QSettings s_;
|
QSettings s_;
|
||||||
bool configloaded_;
|
bool configloaded_;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>596</width>
|
<width>596</width>
|
||||||
<height>638</height>
|
<height>720</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -19,72 +19,119 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Audio output</string>
|
<string>Audio output</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="fieldGrowthPolicy">
|
<item>
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
<layout class="QHBoxLayout" name="horizontalLayout_engine">
|
||||||
</property>
|
<item>
|
||||||
<item row="0" column="0">
|
<widget class="QLabel" name="label_engine">
|
||||||
<widget class="QLabel" name="label_engine">
|
<property name="minimumSize">
|
||||||
<property name="minimumSize">
|
<size>
|
||||||
<size>
|
<width>90</width>
|
||||||
<width>60</width>
|
<height>0</height>
|
||||||
<height>0</height>
|
</size>
|
||||||
</size>
|
</property>
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>Engine</string>
|
||||||
<string>Engine</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="combobox_engine">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="spacer_engine">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item>
|
||||||
<widget class="QComboBox" name="combobox_engine"/>
|
<layout class="QHBoxLayout" name="horizontalLayout_output">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_output">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>90</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Output</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="combobox_output">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="spacer_output">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="label_output">
|
<layout class="QHBoxLayout" name="horizontalLayout_device" stretch="0,0,0,0">
|
||||||
<property name="enabled">
|
<item>
|
||||||
<bool>true</bool>
|
<widget class="QLabel" name="label_device">
|
||||||
</property>
|
<property name="minimumSize">
|
||||||
<property name="minimumSize">
|
<size>
|
||||||
<size>
|
<width>90</width>
|
||||||
<width>60</width>
|
<height>0</height>
|
||||||
<height>0</height>
|
</size>
|
||||||
</size>
|
</property>
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>Device</string>
|
||||||
<string>Output</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QComboBox" name="combobox_output">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_device">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Device</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_device" stretch="0,0">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="combobox_device">
|
<widget class="QComboBox" name="combobox_device">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>240</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -92,32 +139,98 @@
|
|||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>90</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>160</width>
|
<width>160</width>
|
||||||
<height>16777215</height>
|
<height>16777215</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeIncrement">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string extracomment="Leave blank for the default."/>
|
|
||||||
</property>
|
|
||||||
<property name="hint" stdset="0">
|
<property name="hint" stdset="0">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="spacer_device">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_alsaplugin">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_alsaplugin">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>90</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ALSA plugin</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radiobutton_alsa_hw">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>hw</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radiobutton_alsa_plughw">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>plughw</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="spacer_alsaplugin">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -155,7 +268,7 @@
|
|||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_bufferminfill">
|
<widget class="QLabel" name="label_bufferminfill">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Minimum buffer fill</string>
|
<string>&Minimum buffer fill</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ NotificationsSettingsPage::NotificationsSettingsPage(SettingsDialog* dialog)
|
|||||||
pretty_popup_->SetMessage(tr("OSD Preview"), tr("Drag to reposition"), QImage(":/pictures/nocover.png"));
|
pretty_popup_->SetMessage(tr("OSD Preview"), tr("Drag to reposition"), QImage(":/pictures/nocover.png"));
|
||||||
|
|
||||||
ui_->notifications_bg_preset->setItemData(0, QColor(OSDPretty::kPresetBlue), Qt::DecorationRole);
|
ui_->notifications_bg_preset->setItemData(0, QColor(OSDPretty::kPresetBlue), Qt::DecorationRole);
|
||||||
ui_->notifications_bg_preset->setItemData(1, QColor(OSDPretty::kPresetOrange), Qt::DecorationRole);
|
ui_->notifications_bg_preset->setItemData(1, QColor(OSDPretty::kPresetRed), Qt::DecorationRole);
|
||||||
|
|
||||||
// Create and populate the helper menus
|
// Create and populate the helper menus
|
||||||
QMenu *menu = new QMenu(this);
|
QMenu *menu = new QMenu(this);
|
||||||
@@ -186,7 +186,7 @@ void NotificationsSettingsPage::Load() {
|
|||||||
QRgb color = pretty_popup_->background_color();
|
QRgb color = pretty_popup_->background_color();
|
||||||
if (color == OSDPretty::kPresetBlue)
|
if (color == OSDPretty::kPresetBlue)
|
||||||
ui_->notifications_bg_preset->setCurrentIndex(0);
|
ui_->notifications_bg_preset->setCurrentIndex(0);
|
||||||
else if (color == OSDPretty::kPresetOrange)
|
else if (color == OSDPretty::kPresetRed)
|
||||||
ui_->notifications_bg_preset->setCurrentIndex(1);
|
ui_->notifications_bg_preset->setCurrentIndex(1);
|
||||||
else
|
else
|
||||||
ui_->notifications_bg_preset->setCurrentIndex(2);
|
ui_->notifications_bg_preset->setCurrentIndex(2);
|
||||||
@@ -246,7 +246,7 @@ void NotificationsSettingsPage::PrettyColorPresetChanged(int index) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
pretty_popup_->set_background_color(OSDPretty::kPresetOrange);
|
pretty_popup_->set_background_color(OSDPretty::kPresetRed);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|||||||
@@ -307,7 +307,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Strawberry Orange</string>
|
<string>Strawberry Red</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -282,3 +282,10 @@ void SettingsDialog::CurrentItemChanged(QTreeWidgetItem *item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::ComboBoxLoadFromSettings(QSettings &s, QComboBox *combobox, QString setting, QString default_value) {
|
||||||
|
QString value = s.value(setting, default_value).toString();
|
||||||
|
int i = combobox->findData(value);
|
||||||
|
if (i == -1) i = combobox->findData(default_value);
|
||||||
|
combobox->setCurrentIndex(i);
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <QAbstractButton>
|
#include <QAbstractButton>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "widgets/osd.h"
|
#include "widgets/osd.h"
|
||||||
@@ -108,6 +110,8 @@ public:
|
|||||||
|
|
||||||
void set_output_changed(bool output_changed) { output_changed_ = output_changed; }
|
void set_output_changed(bool output_changed) { output_changed_ = output_changed; }
|
||||||
|
|
||||||
|
void ComboBoxLoadFromSettings(QSettings &s, QComboBox *combobox, QString setting, QString default_value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void NotificationPreview(OSD::Behaviour, QString, QString);
|
void NotificationPreview(OSD::Behaviour, QString, QString);
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ TidalSettingsPage::TidalSettingsPage(SettingsDialog *parent)
|
|||||||
connect(ui_->button_login, SIGNAL(clicked()), SLOT(LoginClicked()));
|
connect(ui_->button_login, SIGNAL(clicked()), SLOT(LoginClicked()));
|
||||||
connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(LogoutClicked()));
|
connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(LogoutClicked()));
|
||||||
|
|
||||||
connect(this, SIGNAL(Login(QString, QString, int)), service_, SLOT(SendLogin(QString, QString, int)));
|
connect(this, SIGNAL(Login(QString, QString)), service_, SLOT(SendLogin(QString, QString)));
|
||||||
|
|
||||||
connect(service_, SIGNAL(LoginFailure(QString)), SLOT(LoginFailure(QString)));
|
connect(service_, SIGNAL(LoginFailure(QString)), SLOT(LoginFailure(QString)));
|
||||||
connect(service_, SIGNAL(LoginSuccess()), SLOT(LoginSuccess()));
|
connect(service_, SIGNAL(LoginSuccess()), SLOT(LoginSuccess()));
|
||||||
@@ -56,6 +56,9 @@ TidalSettingsPage::TidalSettingsPage(SettingsDialog *parent)
|
|||||||
ui_->combobox_quality->addItem("High", "HIGH");
|
ui_->combobox_quality->addItem("High", "HIGH");
|
||||||
ui_->combobox_quality->addItem("Lossless", "LOSSLESS");
|
ui_->combobox_quality->addItem("Lossless", "LOSSLESS");
|
||||||
|
|
||||||
|
ui_->combobox_streamurl->addItem("HTTP", "http");
|
||||||
|
ui_->combobox_streamurl->addItem("HTTPS", "https");
|
||||||
|
|
||||||
ui_->combobox_coversize->addItem("160x160", "160x160");
|
ui_->combobox_coversize->addItem("160x160", "160x160");
|
||||||
ui_->combobox_coversize->addItem("320x320", "320x320");
|
ui_->combobox_coversize->addItem("320x320", "320x320");
|
||||||
ui_->combobox_coversize->addItem("640x640", "640x640");
|
ui_->combobox_coversize->addItem("640x640", "640x640");
|
||||||
@@ -71,21 +74,17 @@ void TidalSettingsPage::Load() {
|
|||||||
QSettings s;
|
QSettings s;
|
||||||
|
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
|
|
||||||
ui_->username->setText(s.value("username").toString());
|
ui_->username->setText(s.value("username").toString());
|
||||||
ui_->password->setText(s.value("password").toString());
|
QByteArray password = s.value("password").toByteArray();
|
||||||
|
if (password.isEmpty()) ui_->password->setText("");
|
||||||
QString quality = s.value("quality", "HIGH").toString();
|
else ui_->password->setText(QString::fromUtf8(QByteArray::fromBase64(password)));
|
||||||
ui_->combobox_quality->setCurrentIndex(ui_->combobox_quality->findData(quality));
|
dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_quality, "quality", "HIGH");
|
||||||
|
|
||||||
ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt());
|
ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt());
|
||||||
ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 40).toInt());
|
ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 100).toInt());
|
||||||
ui_->spinbox_songssearchlimit->setValue(s.value("songssearchlimit", 10).toInt());
|
ui_->spinbox_songssearchlimit->setValue(s.value("songssearchlimit", 100).toInt());
|
||||||
ui_->checkbox_fetchalbums->setChecked(s.value("fetchalbums", false).toBool());
|
ui_->checkbox_fetchalbums->setChecked(s.value("fetchalbums", false).toBool());
|
||||||
|
dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_coversize, "coversize", "320x320");
|
||||||
QString coversize = s.value("coversize", "320x320").toString();
|
dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_streamurl, "streamurl", "http");
|
||||||
ui_->combobox_coversize->setCurrentIndex(ui_->combobox_coversize->findData(coversize));
|
|
||||||
|
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
if (service_->authenticated()) ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
|
if (service_->authenticated()) ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
|
||||||
@@ -97,13 +96,14 @@ void TidalSettingsPage::Save() {
|
|||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("username", ui_->username->text());
|
s.setValue("username", ui_->username->text());
|
||||||
s.setValue("password", ui_->password->text());
|
s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64()));
|
||||||
s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex()));
|
s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex()));
|
||||||
s.setValue("searchdelay", ui_->spinbox_searchdelay->value());
|
s.setValue("searchdelay", ui_->spinbox_searchdelay->value());
|
||||||
s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value());
|
s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value());
|
||||||
s.setValue("songssearchlimit", ui_->spinbox_songssearchlimit->value());
|
s.setValue("songssearchlimit", ui_->spinbox_songssearchlimit->value());
|
||||||
s.setValue("fetchalbums", ui_->checkbox_fetchalbums->isChecked());
|
s.setValue("fetchalbums", ui_->checkbox_fetchalbums->isChecked());
|
||||||
s.setValue("coversize", ui_->combobox_coversize->itemData(ui_->combobox_coversize->currentIndex()));
|
s.setValue("coversize", ui_->combobox_coversize->itemData(ui_->combobox_coversize->currentIndex()));
|
||||||
|
s.setValue("streamurl", ui_->combobox_streamurl->itemData(ui_->combobox_streamurl->currentIndex()));
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
service_->ReloadSettings();
|
service_->ReloadSettings();
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class TidalSettingsPage : public SettingsPage {
|
|||||||
bool eventFilter(QObject *object, QEvent *event);
|
bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Login(const QString &username, const QString &password, const int search_id = 0);
|
void Login(const QString &username, const QString &password);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void LoginClicked();
|
void LoginClicked();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>715</width>
|
<width>715</width>
|
||||||
<height>483</height>
|
<height>547</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -281,6 +281,39 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_streamurl">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_streamurl">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stream URL scheme</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="combobox_streamurl"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
#include "core/player.h"
|
||||||
#include "core/closure.h"
|
#include "core/closure.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/mergedproxymodel.h"
|
#include "core/mergedproxymodel.h"
|
||||||
@@ -51,20 +52,22 @@
|
|||||||
#include "internet/internetmodel.h"
|
#include "internet/internetmodel.h"
|
||||||
#include "tidalservice.h"
|
#include "tidalservice.h"
|
||||||
#include "tidalsearch.h"
|
#include "tidalsearch.h"
|
||||||
|
#include "tidalurlhandler.h"
|
||||||
#include "settings/tidalsettingspage.h"
|
#include "settings/tidalsettingspage.h"
|
||||||
|
|
||||||
const Song::Source TidalService::kSource = Song::Source_Tidal;
|
const Song::Source TidalService::kSource = Song::Source_Tidal;
|
||||||
const char *TidalService::kServiceName = "Tidal";
|
|
||||||
const char *TidalService::kApiUrl = "https://listen.tidal.com/v1";
|
const char *TidalService::kApiUrl = "https://listen.tidal.com/v1";
|
||||||
const char *TidalService::kAuthUrl = "https://listen.tidal.com/v1/login/username";
|
const char *TidalService::kAuthUrl = "https://listen.tidal.com/v1/login/username";
|
||||||
const char *TidalService::kResourcesUrl = "http://resources.tidal.com";
|
const char *TidalService::kResourcesUrl = "http://resources.tidal.com";
|
||||||
const char *TidalService::kApiToken = "P5Xbeo5LFvESeDy6";
|
const char *TidalService::kApiTokenB64 = "UDVYYmVvNUxGdkVTZUR5Ng==";
|
||||||
|
const int TidalService::kLoginAttempts = 2;
|
||||||
|
|
||||||
typedef QPair<QString, QString> Param;
|
typedef QPair<QString, QString> Param;
|
||||||
|
|
||||||
TidalService::TidalService(Application *app, InternetModel *parent)
|
TidalService::TidalService(Application *app, InternetModel *parent)
|
||||||
: InternetService(kSource, kServiceName, app, parent, parent),
|
: InternetService(Song::Source_Tidal, "Tidal", "tidal", app, parent, parent),
|
||||||
network_(new NetworkAccessManager(this)),
|
network_(new NetworkAccessManager(this)),
|
||||||
|
url_handler_(new TidalUrlHandler(app, this)),
|
||||||
timer_searchdelay_(new QTimer(this)),
|
timer_searchdelay_(new QTimer(this)),
|
||||||
searchdelay_(1500),
|
searchdelay_(1500),
|
||||||
albumssearchlimit_(1),
|
albumssearchlimit_(1),
|
||||||
@@ -73,14 +76,20 @@ TidalService::TidalService(Application *app, InternetModel *parent)
|
|||||||
user_id_(0),
|
user_id_(0),
|
||||||
pending_search_id_(0),
|
pending_search_id_(0),
|
||||||
next_pending_search_id_(1),
|
next_pending_search_id_(1),
|
||||||
login_sent_(false)
|
search_id_(0),
|
||||||
|
albums_requested_(0),
|
||||||
|
albums_received_(0),
|
||||||
|
login_sent_(false),
|
||||||
|
login_attempts_(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
timer_searchdelay_->setSingleShot(true);
|
timer_searchdelay_->setSingleShot(true);
|
||||||
connect(timer_searchdelay_, SIGNAL(timeout()), SLOT(StartSearch()));
|
connect(timer_searchdelay_, SIGNAL(timeout()), SLOT(StartSearch()));
|
||||||
|
|
||||||
connect(this, SIGNAL(Login(int)), SLOT(SendLogin(int)));
|
connect(this, SIGNAL(Login()), SLOT(SendLogin()));
|
||||||
connect(this, SIGNAL(Login(QString, QString, int)), SLOT(SendLogin(QString, QString, int)));
|
connect(this, SIGNAL(Login(QString, QString)), SLOT(SendLogin(QString, QString)));
|
||||||
|
|
||||||
|
app->player()->RegisterUrlHandler(url_handler_);
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
LoadSessionID();
|
LoadSessionID();
|
||||||
@@ -98,13 +107,16 @@ void TidalService::ReloadSettings() {
|
|||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
||||||
username_ = s.value("username").toString();
|
username_ = s.value("username").toString();
|
||||||
password_ = s.value("password").toString();
|
QByteArray password = s.value("password").toByteArray();
|
||||||
|
if (password.isEmpty()) password_.clear();
|
||||||
|
else password_ = QString::fromUtf8(QByteArray::fromBase64(password));
|
||||||
quality_ = s.value("quality").toString();
|
quality_ = s.value("quality").toString();
|
||||||
searchdelay_ = s.value("searchdelay", 1500).toInt();
|
searchdelay_ = s.value("searchdelay", 1500).toInt();
|
||||||
albumssearchlimit_ = s.value("albumssearchlimit", 40).toInt();
|
albumssearchlimit_ = s.value("albumssearchlimit", 100).toInt();
|
||||||
songssearchlimit_ = s.value("songssearchlimit", 10).toInt();
|
songssearchlimit_ = s.value("songssearchlimit", 100).toInt();
|
||||||
fetchalbums_ = s.value("fetchalbums", false).toBool();
|
fetchalbums_ = s.value("fetchalbums", false).toBool();
|
||||||
coversize_ = s.value("coversize", "320x320").toString();
|
coversize_ = s.value("coversize", "320x320").toString();
|
||||||
|
streamurl_ = s.value("streamurl", "http").toString();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -117,17 +129,18 @@ void TidalService::LoadSessionID() {
|
|||||||
session_id_ = s.value("session_id").toString();
|
session_id_ = s.value("session_id").toString();
|
||||||
user_id_ = s.value("user_id").toInt();
|
user_id_ = s.value("user_id").toInt();
|
||||||
country_code_ = s.value("country_code").toString();
|
country_code_ = s.value("country_code").toString();
|
||||||
|
clientuniquekey_ = Utilities::GetRandomStringWithChars(12).toLower();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::SendLogin(const int search_id) {
|
void TidalService::SendLogin() {
|
||||||
SendLogin(username_, password_, search_id);
|
SendLogin(username_, password_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::SendLogin(const QString &username, const QString &password, const int search_id) {
|
void TidalService::SendLogin(const QString &username, const QString &password) {
|
||||||
|
|
||||||
if (search_id != 0) emit UpdateStatus("Authenticating...");
|
if (search_id_ != 0) emit UpdateStatus("Authenticating...");
|
||||||
|
|
||||||
login_sent_ = true;
|
login_sent_ = true;
|
||||||
login_attempts_++;
|
login_attempts_++;
|
||||||
@@ -138,7 +151,10 @@ void TidalService::SendLogin(const QString &username, const QString &password, c
|
|||||||
typedef QPair<QByteArray, QByteArray> EncodedArg;
|
typedef QPair<QByteArray, QByteArray> EncodedArg;
|
||||||
typedef QList<EncodedArg> EncodedArgList;
|
typedef QList<EncodedArg> EncodedArgList;
|
||||||
|
|
||||||
ArgList args = ArgList() <<Arg("token", kApiToken) << Arg("username", username) << Arg("password", password) << Arg("clientVersion", "2.2.1--7");
|
ArgList args = ArgList() << Arg("token", QByteArray::fromBase64(kApiTokenB64))
|
||||||
|
<< Arg("username", username)
|
||||||
|
<< Arg("password", password)
|
||||||
|
<< Arg("clientUniqueKey", clientuniquekey_);
|
||||||
|
|
||||||
QStringList query_items;
|
QStringList query_items;
|
||||||
QUrlQuery url_query;
|
QUrlQuery url_query;
|
||||||
@@ -152,12 +168,13 @@ void TidalService::SendLogin(const QString &username, const QString &password, c
|
|||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
|
|
||||||
req.setRawHeader("Origin", "http://listen.tidal.com");
|
req.setRawHeader("Origin", "http://listen.tidal.com");
|
||||||
|
req.setRawHeader("X-Tidal-Token", QByteArray::fromBase64(kApiTokenB64));
|
||||||
QNetworkReply *reply = network_->post(req, url_query.toString(QUrl::FullyEncoded).toUtf8());
|
QNetworkReply *reply = network_->post(req, url_query.toString(QUrl::FullyEncoded).toUtf8());
|
||||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleAuthReply(QNetworkReply*, int)), reply, search_id);
|
NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleAuthReply(QNetworkReply*)), reply);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
void TidalService::HandleAuthReply(QNetworkReply *reply) {
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
@@ -167,7 +184,7 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
if (reply->error() < 200) {
|
if (reply->error() < 200) {
|
||||||
// This is a network error, there is nothing more to do.
|
// This is a network error, there is nothing more to do.
|
||||||
QString failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
QString failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -189,7 +206,7 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
else {
|
else {
|
||||||
failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
||||||
}
|
}
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -201,21 +218,21 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
|
|
||||||
if (error.error != QJsonParseError::NoError) {
|
if (error.error != QJsonParseError::NoError) {
|
||||||
QString failure_reason("Authentication reply from server missing Json data.");
|
QString failure_reason("Authentication reply from server missing Json data.");
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_doc.isNull() || json_doc.isEmpty()) {
|
if (json_doc.isNull() || json_doc.isEmpty()) {
|
||||||
QString failure_reason("Authentication reply from server has empty Json document.");
|
QString failure_reason("Authentication reply from server has empty Json document.");
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_doc.isObject()) {
|
if (!json_doc.isObject()) {
|
||||||
QString failure_reason("Authentication reply from server has Json document that is not an object.");
|
QString failure_reason("Authentication reply from server has Json document that is not an object.");
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -223,14 +240,14 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
QJsonObject json_obj = json_doc.object();
|
QJsonObject json_obj = json_doc.object();
|
||||||
if (json_obj.isEmpty()) {
|
if (json_obj.isEmpty()) {
|
||||||
QString failure_reason("Authentication reply from server has empty Json object.");
|
QString failure_reason("Authentication reply from server has empty Json object.");
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !json_obj.contains("userId") || !json_obj.contains("sessionId") || !json_obj.contains("countryCode") ) {
|
if ( !json_obj.contains("userId") || !json_obj.contains("sessionId") || !json_obj.contains("countryCode") ) {
|
||||||
QString failure_reason = tr("Authentication reply from server is missing userId, sessionId or countryCode");
|
QString failure_reason("Authentication reply from server is missing userId, sessionId or countryCode");
|
||||||
if (search_id != 0) Error(failure_reason);
|
Error(failure_reason);
|
||||||
emit LoginFailure(failure_reason);
|
emit LoginFailure(failure_reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -238,6 +255,7 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
country_code_ = json_obj["countryCode"].toString();
|
country_code_ = json_obj["countryCode"].toString();
|
||||||
session_id_ = json_obj["sessionId"].toString();
|
session_id_ = json_obj["sessionId"].toString();
|
||||||
user_id_ = json_obj["userId"].toInt();
|
user_id_ = json_obj["userId"].toInt();
|
||||||
|
clientuniquekey_ = Utilities::GetRandomStringWithChars(12).toLower();
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
||||||
@@ -248,10 +266,16 @@ void TidalService::HandleAuthReply(QNetworkReply *reply, int search_id) {
|
|||||||
|
|
||||||
qLog(Debug) << "Tidal: Login successful" << "user id" << user_id_ << "session id" << session_id_ << "country code" << country_code_;
|
qLog(Debug) << "Tidal: Login successful" << "user id" << user_id_ << "session id" << session_id_ << "country code" << country_code_;
|
||||||
|
|
||||||
if (search_id != 0) {
|
login_attempts_ = 0;
|
||||||
qLog(Debug) << "Tidal: Resuming search";
|
|
||||||
|
if (search_id_ != 0) {
|
||||||
|
qLog(Debug) << "Tidal: Resuming search" << search_id_;
|
||||||
SendSearch();
|
SendSearch();
|
||||||
}
|
}
|
||||||
|
if (!stream_request_url_.isEmpty()) {
|
||||||
|
qLog(Debug) << "Tidal: Resuming get stream url" << stream_request_url_;
|
||||||
|
emit GetStreamURL(stream_request_url_);
|
||||||
|
}
|
||||||
|
|
||||||
emit LoginSuccess();
|
emit LoginSuccess();
|
||||||
|
|
||||||
@@ -295,6 +319,8 @@ QNetworkReply *TidalService::CreateRequest(const QString &ressource_name, const
|
|||||||
QUrl url(kApiUrl + QString("/") + ressource_name);
|
QUrl url(kApiUrl + QString("/") + ressource_name);
|
||||||
url.setQuery(url_query);
|
url.setQuery(url_query);
|
||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
|
req.setRawHeader("Origin", "http://listen.tidal.com");
|
||||||
|
req.setRawHeader("X-Tidal-SessionId", session_id_.toUtf8());
|
||||||
QNetworkReply *reply = network_->get(req);
|
QNetworkReply *reply = network_->get(req);
|
||||||
|
|
||||||
//qLog(Debug) << "Tidal: Sending request" << url;
|
//qLog(Debug) << "Tidal: Sending request" << url;
|
||||||
@@ -303,7 +329,7 @@ QNetworkReply *TidalService::CreateRequest(const QString &ressource_name, const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject TidalService::ExtractJsonObj(QNetworkReply *reply, bool sendlogin) {
|
QJsonObject TidalService::ExtractJsonObj(QNetworkReply *reply, const bool sendlogin) {
|
||||||
|
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
|
|
||||||
@@ -334,14 +360,15 @@ QJsonObject TidalService::ExtractJsonObj(QNetworkReply *reply, bool sendlogin) {
|
|||||||
else {
|
else {
|
||||||
failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
failure_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
||||||
}
|
}
|
||||||
|
qLog(Debug) << reply->error();
|
||||||
if (reply->error() == QNetworkReply::ContentAccessDenied || reply->error() == QNetworkReply::ContentOperationNotPermittedError || reply->error() == QNetworkReply::AuthenticationRequiredError) {
|
if (reply->error() == QNetworkReply::ContentAccessDenied || reply->error() == QNetworkReply::ContentOperationNotPermittedError || reply->error() == QNetworkReply::AuthenticationRequiredError) {
|
||||||
// Session is probably expired, attempt to login once
|
// Session is probably expired, attempt to login once
|
||||||
Logout();
|
Logout();
|
||||||
if (sendlogin && login_attempts_ < 1 && !username_.isEmpty() && !password_.isEmpty()) {
|
if (sendlogin && login_attempts_ < kLoginAttempts && !username_.isEmpty() && !password_.isEmpty()) {
|
||||||
qLog(Error) << "Tidal:" << failure_reason;
|
qLog(Error) << "Tidal:" << failure_reason;
|
||||||
qLog(Error) << "Tidal:" << QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
qLog(Error) << "Tidal:" << QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
|
||||||
qLog(Error) << "Tidal:" << "Attempting to login.";
|
qLog(Error) << "Tidal:" << "Attempting to login.";
|
||||||
emit Login(search_id_);
|
emit Login();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Error(failure_reason);
|
Error(failure_reason);
|
||||||
@@ -439,7 +466,7 @@ void TidalService::StartSearch() {
|
|||||||
search_text_ = pending_search_text_;
|
search_text_ = pending_search_text_;
|
||||||
|
|
||||||
if (authenticated()) SendSearch();
|
if (authenticated()) SendSearch();
|
||||||
else emit Login(username_, password_, search_id_);
|
else emit Login(username_, password_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,9 +478,7 @@ void TidalService::ClearSearch() {
|
|||||||
search_text_.clear();
|
search_text_.clear();
|
||||||
search_error_.clear();
|
search_error_.clear();
|
||||||
albums_requested_ = 0;
|
albums_requested_ = 0;
|
||||||
songs_requested_ = 0;
|
|
||||||
albums_received_ = 0;
|
albums_received_ = 0;
|
||||||
songs_received_ = 0;
|
|
||||||
requests_album_.clear();
|
requests_album_.clear();
|
||||||
requests_song_.clear();
|
requests_song_.clear();
|
||||||
login_attempts_ = 0;
|
login_attempts_ = 0;
|
||||||
@@ -525,9 +550,7 @@ void TidalService::SearchFinished(QNetworkReply *reply, int id) {
|
|||||||
// This was a tracks search
|
// This was a tracks search
|
||||||
if (!fetchalbums_) {
|
if (!fetchalbums_) {
|
||||||
Song song = ParseSong(0, value);
|
Song song = ParseSong(0, value);
|
||||||
requests_song_.insert(song.id(), song);
|
songs_ << song;
|
||||||
songs_requested_++;
|
|
||||||
GetStreamURL(0, song.id());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QJsonValue json_value_album = json_obj["album"];
|
QJsonValue json_value_album = json_obj["album"];
|
||||||
@@ -573,12 +596,13 @@ void TidalService::SearchFinished(QNetworkReply *reply, int id) {
|
|||||||
QString artist = json_artist["name"].toString();
|
QString artist = json_artist["name"].toString();
|
||||||
|
|
||||||
QString quality = json_obj["audioQuality"].toString();
|
QString quality = json_obj["audioQuality"].toString();
|
||||||
|
QString copyright = json_obj["copyright"].toString();
|
||||||
|
|
||||||
//qLog(Debug) << "Tidal:" << artist << album << quality;
|
//qLog(Debug) << "Tidal:" << artist << album << quality << copyright;
|
||||||
|
|
||||||
QString artist_album(QString("%1-%2").arg(artist).arg(album));
|
QString artist_album(QString("%1-%2").arg(artist).arg(album));
|
||||||
if (albums.contains(artist_album)) {
|
if (albums.contains(artist_album)) {
|
||||||
qLog(Debug) << "Tidal: Skipping duplicate album" << artist << album << quality;
|
qLog(Debug) << "Tidal: Skipping duplicate album" << artist << album << quality << copyright;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
albums.insert(0, artist_album);
|
albums.insert(0, artist_album);
|
||||||
@@ -594,11 +618,6 @@ void TidalService::SearchFinished(QNetworkReply *reply, int id) {
|
|||||||
emit ProgressSetMaximum(albums_requested_);
|
emit ProgressSetMaximum(albums_requested_);
|
||||||
emit UpdateProgress(0);
|
emit UpdateProgress(0);
|
||||||
}
|
}
|
||||||
else if (songs_requested_ > 0) {
|
|
||||||
emit UpdateStatus(QString("Retriving %1 song%2...").arg(songs_requested_).arg(songs_requested_ == 1 ? "" : "s"));
|
|
||||||
emit ProgressSetMaximum(songs_requested_);
|
|
||||||
emit UpdateProgress(songs_received_);
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckFinish();
|
CheckFinish();
|
||||||
|
|
||||||
@@ -607,11 +626,7 @@ void TidalService::SearchFinished(QNetworkReply *reply, int id) {
|
|||||||
void TidalService::GetAlbum(const int album_id) {
|
void TidalService::GetAlbum(const int album_id) {
|
||||||
|
|
||||||
QList<Param> parameters;
|
QList<Param> parameters;
|
||||||
parameters << Param("token", session_id_)
|
|
||||||
<< Param("soundQuality", quality_);
|
|
||||||
|
|
||||||
QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(album_id), parameters);
|
QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(album_id), parameters);
|
||||||
|
|
||||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetAlbumFinished(QNetworkReply*, int, int)), reply, search_id_, album_id);
|
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetAlbumFinished(QNetworkReply*, int, int)), reply, search_id_, album_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -649,15 +664,7 @@ void TidalService::GetAlbumFinished(QNetworkReply *reply, int search_id, int alb
|
|||||||
QString album_full(QString("%1 - (Disc %2)").arg(song.album()).arg(song.disc()));
|
QString album_full(QString("%1 - (Disc %2)").arg(song.album()).arg(song.disc()));
|
||||||
song.set_album(album_full);
|
song.set_album(album_full);
|
||||||
}
|
}
|
||||||
requests_song_.insert(song.id(), song);
|
songs_ << song;
|
||||||
songs_requested_++;
|
|
||||||
GetStreamURL(album_id, song.id());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (albums_requested_ <= albums_received_) {
|
|
||||||
emit UpdateStatus(QString("Retriving %1 song%2...").arg(songs_requested_).arg(songs_requested_ == 1 ? "" : "s"));
|
|
||||||
emit ProgressSetMaximum(songs_requested_);
|
|
||||||
emit UpdateProgress(songs_received_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckFinish();
|
CheckFinish();
|
||||||
@@ -702,10 +709,9 @@ Song TidalService::ParseSong(const int album_id_requested, const QJsonValue &val
|
|||||||
QJsonArray json_artists = json_obj["artists"].toArray();
|
QJsonArray json_artists = json_obj["artists"].toArray();
|
||||||
|
|
||||||
int song_id = json_obj["id"].toInt();
|
int song_id = json_obj["id"].toInt();
|
||||||
if (requests_song_.contains(song_id)) return requests_song_.value(song_id);
|
|
||||||
|
|
||||||
QString title = json_obj["title"].toString();
|
QString title = json_obj["title"].toString();
|
||||||
QString url = json_obj["url"].toString();
|
QString urlstr = json_obj["url"].toString();
|
||||||
int track = json_obj["trackNumber"].toInt();
|
int track = json_obj["trackNumber"].toInt();
|
||||||
int disc = json_obj["volumeNumber"].toInt();
|
int disc = json_obj["volumeNumber"].toInt();
|
||||||
bool allow_streaming = json_obj["allowStreaming"].toBool();
|
bool allow_streaming = json_obj["allowStreaming"].toBool();
|
||||||
@@ -760,9 +766,6 @@ Song TidalService::ParseSong(const int album_id_requested, const QJsonValue &val
|
|||||||
song.set_title(title);
|
song.set_title(title);
|
||||||
song.set_track(track);
|
song.set_track(track);
|
||||||
song.set_disc(disc);
|
song.set_disc(disc);
|
||||||
song.set_bitrate(0);
|
|
||||||
song.set_samplerate(0);
|
|
||||||
song.set_bitdepth(0);
|
|
||||||
|
|
||||||
QVariant q_duration = json_duration.toVariant();
|
QVariant q_duration = json_duration.toVariant();
|
||||||
if (q_duration.isValid()) {
|
if (q_duration.isValid()) {
|
||||||
@@ -773,81 +776,81 @@ Song TidalService::ParseSong(const int album_id_requested, const QJsonValue &val
|
|||||||
cover = cover.replace("-", "/");
|
cover = cover.replace("-", "/");
|
||||||
QUrl cover_url (QString("%1/images/%2/%3.jpg").arg(kResourcesUrl).arg(cover).arg(coversize_));
|
QUrl cover_url (QString("%1/images/%2/%3.jpg").arg(kResourcesUrl).arg(cover).arg(coversize_));
|
||||||
song.set_art_automatic(cover_url.toEncoded());
|
song.set_art_automatic(cover_url.toEncoded());
|
||||||
|
|
||||||
|
QUrl url;
|
||||||
|
url.setScheme(url_handler_->scheme());
|
||||||
|
url.setPath(QString::number(song_id));
|
||||||
|
song.set_url(url);
|
||||||
|
|
||||||
song.set_valid(true);
|
song.set_valid(true);
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::GetStreamURL(const int album_id, const int song_id) {
|
void TidalService::GetStreamURL(const QUrl &url) {
|
||||||
|
|
||||||
|
stream_request_url_ = url;
|
||||||
|
int song_id = url.path().toInt();
|
||||||
|
requests_song_.insert(song_id, url);
|
||||||
|
|
||||||
QList<Param> parameters;
|
QList<Param> parameters;
|
||||||
parameters << Param("token", session_id_)
|
parameters << Param("soundQuality", quality_);
|
||||||
<< Param("soundQuality", quality_);
|
|
||||||
|
|
||||||
QNetworkReply *reply = CreateRequest(QString("tracks/%1/streamUrl").arg(song_id), parameters);
|
QNetworkReply *reply = CreateRequest(QString("tracks/%1/streamUrl").arg(song_id), parameters);
|
||||||
|
|
||||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetStreamURLFinished(QNetworkReply*, int, int)), reply, search_id_, song_id);
|
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetStreamURLFinished(QNetworkReply*, int, QUrl)), reply, song_id, url);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::GetStreamURLFinished(QNetworkReply *reply, const int search_id, const int song_id) {
|
void TidalService::GetStreamURLFinished(QNetworkReply *reply, const int song_id, const QUrl original_url) {
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
if (requests_song_.contains(song_id)) requests_song_.remove(song_id);
|
||||||
|
if (original_url != stream_request_url_) return;
|
||||||
|
|
||||||
if (search_id != search_id_) return;
|
QJsonObject json_obj = ExtractJsonObj(reply, true);
|
||||||
|
|
||||||
if (!requests_song_.contains(song_id)) {
|
|
||||||
CheckFinish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Song song = requests_song_.value(song_id);
|
|
||||||
songs_received_++;
|
|
||||||
|
|
||||||
if (albums_requested_ <= albums_received_) {
|
|
||||||
emit UpdateProgress(songs_received_);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject json_obj = ExtractJsonObj(reply);
|
|
||||||
if (json_obj.isEmpty()) {
|
if (json_obj.isEmpty()) {
|
||||||
requests_song_.remove(song_id);
|
if (!stream_request_url_.isEmpty() && !login_sent_) {
|
||||||
CheckFinish();
|
emit StreamURLFinished(QUrl(), Song::FileType_Stream);
|
||||||
|
stream_request_url_ = QUrl();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("url") || !json_obj.contains("codec")) {
|
if (!json_obj.contains("url") || !json_obj.contains("codec")) {
|
||||||
qLog(Error) << "Tidal: Invalid Json reply, stream missing url or codec.";
|
qLog(Error) << "Tidal: Invalid Json reply, stream missing url or codec.";
|
||||||
qLog(Debug) << json_obj;
|
qLog(Debug) << json_obj;
|
||||||
requests_song_.remove(song_id);
|
emit StreamURLFinished(QUrl(), Song::FileType_Stream);
|
||||||
CheckFinish();
|
stream_request_url_ = QUrl();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
song.set_url(QUrl(json_obj["url"].toString()));
|
stream_request_url_ = QUrl();
|
||||||
|
|
||||||
QString codec = json_obj["codec"].toString().toLower();
|
QUrl new_url(json_obj["url"].toString());
|
||||||
song.set_filetype(Song::FiletypeByExtension(codec));
|
QString codec(json_obj["codec"].toString().toLower());
|
||||||
if (song.filetype() == Song::FileType_Unknown) {
|
Song::FileType filetype(Song::FiletypeByExtension(codec));
|
||||||
|
if (filetype == Song::FileType_Unknown) {
|
||||||
qLog(Debug) << "Tidal: Unknown codec" << codec;
|
qLog(Debug) << "Tidal: Unknown codec" << codec;
|
||||||
song.set_filetype(Song::FileType_Stream);
|
filetype = Song::FileType_Stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
song.set_valid(true);
|
if (new_url.scheme() != streamurl_) new_url.setScheme(streamurl_);
|
||||||
|
|
||||||
//qLog(Debug) << song.artist() << song.album() << song.title() << song.url() << song.filetype();
|
emit StreamURLFinished(new_url, filetype);
|
||||||
|
|
||||||
songs_ << song;
|
|
||||||
|
|
||||||
requests_song_.remove(song_id);
|
|
||||||
|
|
||||||
CheckFinish();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::CheckFinish() {
|
void TidalService::CheckFinish() {
|
||||||
|
|
||||||
if (!login_sent_ && albums_requested_ <= albums_received_ && songs_requested_ <= songs_received_) {
|
if (search_id_ == 0) return;
|
||||||
if (songs_.isEmpty()) emit SearchError(search_id_, search_error_);
|
|
||||||
|
if (!login_sent_ && albums_requested_ <= albums_received_) {
|
||||||
|
if (songs_.isEmpty()) {
|
||||||
|
if (search_error_.isEmpty()) emit SearchError(search_id_, "Unknown error");
|
||||||
|
else emit SearchError(search_id_, search_error_);
|
||||||
|
}
|
||||||
else emit SearchResults(search_id_, songs_);
|
else emit SearchResults(search_id_, songs_);
|
||||||
ClearSearch();
|
ClearSearch();
|
||||||
}
|
}
|
||||||
@@ -857,6 +860,15 @@ void TidalService::CheckFinish() {
|
|||||||
void TidalService::Error(QString error, QString debug) {
|
void TidalService::Error(QString error, QString debug) {
|
||||||
qLog(Error) << "Tidal:" << error;
|
qLog(Error) << "Tidal:" << error;
|
||||||
if (!debug.isEmpty()) qLog(Debug) << debug;
|
if (!debug.isEmpty()) qLog(Debug) << debug;
|
||||||
search_error_ = error;
|
if (search_id_ != 0) {
|
||||||
CheckFinish();
|
if (!error.isEmpty()) {
|
||||||
|
search_error_ += error;
|
||||||
|
search_error_ += "<br />";
|
||||||
|
}
|
||||||
|
CheckFinish();
|
||||||
|
}
|
||||||
|
if (!stream_request_url_.isEmpty() && !login_sent_) {
|
||||||
|
emit StreamURLFinished(QUrl(), Song::FileType_Stream);
|
||||||
|
stream_request_url_ = QUrl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
#include "settings/tidalsettingspage.h"
|
#include "settings/tidalsettingspage.h"
|
||||||
|
|
||||||
class NetworkAccessManager;
|
class NetworkAccessManager;
|
||||||
|
class TidalUrlHandler;
|
||||||
|
|
||||||
class TidalService : public InternetService {
|
class TidalService : public InternetService {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -48,7 +50,7 @@ class TidalService : public InternetService {
|
|||||||
~TidalService();
|
~TidalService();
|
||||||
|
|
||||||
static const Song::Source kSource;
|
static const Song::Source kSource;
|
||||||
static const char *kServiceName;
|
static const int kLoginAttempts;
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
@@ -59,9 +61,11 @@ class TidalService : public InternetService {
|
|||||||
const bool login_sent() { return login_sent_; }
|
const bool login_sent() { return login_sent_; }
|
||||||
const bool authenticated() { return (!session_id_.isEmpty() && !country_code_.isEmpty()); }
|
const bool authenticated() { return (!session_id_.isEmpty() && !country_code_.isEmpty()); }
|
||||||
|
|
||||||
|
void GetStreamURL(const QUrl &url);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Login(const int search_id = 0);
|
void Login();
|
||||||
void Login(const QString &username, const QString &password, const int search_id = 0);
|
void Login(const QString &username, const QString &password);
|
||||||
void LoginSuccess();
|
void LoginSuccess();
|
||||||
void LoginFailure(QString failure_reason);
|
void LoginFailure(QString failure_reason);
|
||||||
void SearchResults(int id, SongList songs);
|
void SearchResults(int id, SongList songs);
|
||||||
@@ -69,18 +73,20 @@ class TidalService : public InternetService {
|
|||||||
void UpdateStatus(QString text);
|
void UpdateStatus(QString text);
|
||||||
void ProgressSetMaximum(int max);
|
void ProgressSetMaximum(int max);
|
||||||
void UpdateProgress(int max);
|
void UpdateProgress(int max);
|
||||||
|
void GetStreamURLFinished(QNetworkReply *reply, const QUrl url);
|
||||||
|
void StreamURLFinished(const QUrl url, const Song::FileType);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void ShowConfig();
|
void ShowConfig();
|
||||||
void SendLogin(const QString &username, const QString &password, const int search_id = 0);
|
void SendLogin(const QString &username, const QString &password);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SendLogin(const int search_id = 0);
|
void SendLogin();
|
||||||
void HandleAuthReply(QNetworkReply *reply, int search_id);
|
void HandleAuthReply(QNetworkReply *reply);
|
||||||
void StartSearch();
|
void StartSearch();
|
||||||
void SearchFinished(QNetworkReply *reply, int search_id);
|
void SearchFinished(QNetworkReply *reply, int search_id);
|
||||||
void GetAlbumFinished(QNetworkReply *reply, int search_id, int album_id);
|
void GetAlbumFinished(QNetworkReply *reply, int search_id, int album_id);
|
||||||
void GetStreamURLFinished(QNetworkReply *reply, const int search_id, const int song_id);
|
void GetStreamURLFinished(QNetworkReply *reply, const int song_id, const QUrl original_url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClearSearch();
|
void ClearSearch();
|
||||||
@@ -91,16 +97,16 @@ class TidalService : public InternetService {
|
|||||||
void SendSearch();
|
void SendSearch();
|
||||||
void GetAlbum(const int album_id);
|
void GetAlbum(const int album_id);
|
||||||
Song ParseSong(const int album_id_requested, const QJsonValue &value);
|
Song ParseSong(const int album_id_requested, const QJsonValue &value);
|
||||||
void GetStreamURL(const int album_id, const int song_id);
|
|
||||||
void CheckFinish();
|
void CheckFinish();
|
||||||
void Error(QString error, QString debug = "");
|
void Error(QString error, QString debug = QString());
|
||||||
|
|
||||||
static const char *kApiUrl;
|
static const char *kApiUrl;
|
||||||
static const char *kAuthUrl;
|
static const char *kAuthUrl;
|
||||||
static const char *kResourcesUrl;
|
static const char *kResourcesUrl;
|
||||||
static const char *kApiToken;
|
static const char *kApiTokenB64;
|
||||||
|
|
||||||
NetworkAccessManager *network_;
|
NetworkAccessManager *network_;
|
||||||
|
TidalUrlHandler *url_handler_;
|
||||||
QTimer *timer_searchdelay_;
|
QTimer *timer_searchdelay_;
|
||||||
|
|
||||||
QString username_;
|
QString username_;
|
||||||
@@ -111,9 +117,11 @@ class TidalService : public InternetService {
|
|||||||
int songssearchlimit_;
|
int songssearchlimit_;
|
||||||
bool fetchalbums_;
|
bool fetchalbums_;
|
||||||
QString coversize_;
|
QString coversize_;
|
||||||
|
QString streamurl_;
|
||||||
QString session_id_;
|
QString session_id_;
|
||||||
quint64 user_id_;
|
quint64 user_id_;
|
||||||
QString country_code_;
|
QString country_code_;
|
||||||
|
QString clientuniquekey_;
|
||||||
|
|
||||||
int pending_search_id_;
|
int pending_search_id_;
|
||||||
int next_pending_search_id_;
|
int next_pending_search_id_;
|
||||||
@@ -123,15 +131,14 @@ class TidalService : public InternetService {
|
|||||||
int search_id_;
|
int search_id_;
|
||||||
QString search_text_;
|
QString search_text_;
|
||||||
QHash<int, int> requests_album_;
|
QHash<int, int> requests_album_;
|
||||||
QHash<int, Song> requests_song_;
|
QHash<int, QUrl> requests_song_;
|
||||||
int albums_requested_;
|
int albums_requested_;
|
||||||
int albums_received_;
|
int albums_received_;
|
||||||
int songs_requested_;
|
|
||||||
int songs_received_;
|
|
||||||
SongList songs_;
|
SongList songs_;
|
||||||
QString search_error_;
|
QString search_error_;
|
||||||
bool login_sent_;
|
bool login_sent_;
|
||||||
int login_attempts_;
|
int login_attempts_;
|
||||||
|
QUrl stream_request_url_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
63
src/tidal/tidalurlhandler.cpp
Normal file
63
src/tidal/tidalurlhandler.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* 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 <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "core/taskmanager.h"
|
||||||
|
#include "core/iconloader.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/song.h"
|
||||||
|
#include "tidal/tidalservice.h"
|
||||||
|
#include "tidalurlhandler.h"
|
||||||
|
|
||||||
|
TidalUrlHandler::TidalUrlHandler(
|
||||||
|
Application *app, TidalService *service)
|
||||||
|
: UrlHandler(service), app_(app), service_(service), task_id_(-1) {
|
||||||
|
|
||||||
|
connect(service, SIGNAL(StreamURLFinished(QUrl, Song::FileType)), this, SLOT(GetStreamURLFinished(QUrl, Song::FileType)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
UrlHandler::LoadResult TidalUrlHandler::StartLoading(const QUrl &url) {
|
||||||
|
|
||||||
|
LoadResult ret(url);
|
||||||
|
if (task_id_ != -1) return ret;
|
||||||
|
last_original_url_ = url;
|
||||||
|
task_id_ = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
|
||||||
|
service_->GetStreamURL(url);
|
||||||
|
ret.type_ = LoadResult::WillLoadAsynchronously;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TidalUrlHandler::GetStreamURLFinished(QUrl url, Song::FileType filetype) {
|
||||||
|
|
||||||
|
if (task_id_ == -1) return;
|
||||||
|
CancelTask();
|
||||||
|
emit AsyncLoadComplete(LoadResult(last_original_url_, LoadResult::TrackAvailable, url, filetype));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TidalUrlHandler::CancelTask() {
|
||||||
|
app_->task_manager()->SetTaskFinished(task_id_);
|
||||||
|
task_id_ = -1;
|
||||||
|
}
|
||||||
56
src/tidal/tidalurlhandler.h
Normal file
56
src/tidal/tidalurlhandler.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Strawberry Music Player
|
||||||
|
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||||
|
*
|
||||||
|
* 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 TIDALURLHANDLER_H
|
||||||
|
#define TIDALURLHANDLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "core/urlhandler.h"
|
||||||
|
#include "core/song.h"
|
||||||
|
#include "tidal/tidalservice.h"
|
||||||
|
|
||||||
|
class Application;
|
||||||
|
class TidalService;
|
||||||
|
|
||||||
|
class TidalUrlHandler : public UrlHandler {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TidalUrlHandler(Application *app, TidalService *service);
|
||||||
|
|
||||||
|
QString scheme() const { return service_->url_scheme(); }
|
||||||
|
LoadResult StartLoading(const QUrl &url);
|
||||||
|
|
||||||
|
void CancelTask();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void GetStreamURLFinished(QUrl url, Song::FileType filetype);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Application *app_;
|
||||||
|
TidalService *service_;
|
||||||
|
int task_id_;
|
||||||
|
QUrl last_original_url_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -233,9 +233,9 @@ QModelIndex GroupedIconView::indexAt(const QPoint &p) const {
|
|||||||
void GroupedIconView::paintEvent(QPaintEvent *e) {
|
void GroupedIconView::paintEvent(QPaintEvent *e) {
|
||||||
// This code was adapted from QListView::paintEvent(), changed to use the visualRect() of items, and to draw headers.
|
// This code was adapted from QListView::paintEvent(), changed to use the visualRect() of items, and to draw headers.
|
||||||
|
|
||||||
QStyleOptionViewItemV4 option(viewOptions());
|
QStyleOptionViewItem option(viewOptions());
|
||||||
if (isWrapping())
|
if (isWrapping())
|
||||||
option.features = QStyleOptionViewItemV2::WrapText;
|
option.features = QStyleOptionViewItem::WrapText;
|
||||||
option.locale = locale();
|
option.locale = locale();
|
||||||
option.locale.setNumberOptions(QLocale::OmitGroupSeparator);
|
option.locale.setNumberOptions(QLocale::OmitGroupSeparator);
|
||||||
option.widget = this;
|
option.widget = this;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const int OSDPretty::kMaxIconSize = 100;
|
|||||||
const int OSDPretty::kSnapProximity = 20;
|
const int OSDPretty::kSnapProximity = 20;
|
||||||
|
|
||||||
const QRgb OSDPretty::kPresetBlue = qRgb(102, 150, 227);
|
const QRgb OSDPretty::kPresetBlue = qRgb(102, 150, 227);
|
||||||
const QRgb OSDPretty::kPresetOrange = qRgb(254, 156, 67);
|
const QRgb OSDPretty::kPresetRed = qRgb(202, 22, 16);
|
||||||
|
|
||||||
|
|
||||||
OSDPretty::OSDPretty(Mode mode, QWidget *parent)
|
OSDPretty::OSDPretty(Mode mode, QWidget *parent)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class OSDPretty : public QWidget {
|
|||||||
static const int kSnapProximity;
|
static const int kSnapProximity;
|
||||||
|
|
||||||
static const QRgb kPresetBlue;
|
static const QRgb kPresetBlue;
|
||||||
static const QRgb kPresetOrange;
|
static const QRgb kPresetRed;
|
||||||
|
|
||||||
static bool IsTransparencyAvailable();
|
static bool IsTransparencyAvailable();
|
||||||
|
|
||||||
|
|||||||
@@ -273,9 +273,8 @@ void PlayingWidget::SongChanged(const Song &song) {
|
|||||||
|
|
||||||
void PlayingWidget::AlbumArtLoaded(const Song &song, const QString &, const QImage &image) {
|
void PlayingWidget::AlbumArtLoaded(const Song &song, const QString &, const QImage &image) {
|
||||||
|
|
||||||
if (!playing_) return;
|
if (!playing_ || song.id() != song_playing_.id() || song.url() != song_playing_.url() || song.effective_albumartist() != song_playing_.effective_albumartist() || song.effective_album() != song_playing_.effective_album() || song.title() != song_playing_.title()) return;
|
||||||
|
if (timeline_fade_->state() == QTimeLine::Running && image == image_original_) return;
|
||||||
if (song.effective_albumartist() != song_playing_.effective_albumartist() || song.effective_album() != song_playing_.effective_album() || song.title() != song_playing_.title()) return;
|
|
||||||
|
|
||||||
active_ = true;
|
active_ = true;
|
||||||
downloading_covers_ = false;
|
downloading_covers_ = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user