mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-06 12:10:47 +02:00
Compare commits
85 Commits
woah
...
linkparser
Author | SHA1 | Date | |
---|---|---|---|
|
8ddc270c8c | ||
|
47e09fbaca | ||
|
0585acc869 | ||
|
8c8cd88388 | ||
|
9e91ad6549 | ||
|
192627a4ea | ||
|
ee1f19c34e | ||
|
a41af0ed7f | ||
|
feffda8339 | ||
|
4b7f8929fd | ||
|
acdd0e3b9f | ||
|
4ba32e0add | ||
|
9b1b7be207 | ||
|
d7e5ce6e4e | ||
|
684e5f3a58 | ||
|
3d0584a351 | ||
|
2a43e9aba5 | ||
|
cde395edf0 | ||
|
5aa875c40a | ||
|
e4146c98c7 | ||
|
d2dc01e6a3 | ||
|
8fbd3b9872 | ||
|
ac4debbe02 | ||
|
c4197374ca | ||
|
a36287c2ed | ||
|
054650743d | ||
|
ea55329c67 | ||
|
5a45bd0882 | ||
|
5395908cbe | ||
|
213bf1cd08 | ||
|
efc31e6246 | ||
|
3d511b65e1 | ||
|
5a34bae757 | ||
|
0223fd5992 | ||
|
66a2d3cb88 | ||
|
75427a7af2 | ||
|
92c66d7252 | ||
|
2afc578d7a | ||
|
0791937032 | ||
|
45c96e7367 | ||
|
4d351168da | ||
|
86f08b307e | ||
|
99fe5c8e8e | ||
|
daf3034d99 | ||
|
e8d73fe0cc | ||
|
de78768be6 | ||
|
d0c1d83f90 | ||
|
ca379868dc | ||
|
cf7194407b | ||
|
365a021a29 | ||
|
c39750d814 | ||
|
6d12f03023 | ||
|
03935f26a9 | ||
|
e697303743 | ||
|
e4f55da2b2 | ||
|
576c91eb19 | ||
|
6823b57823 | ||
|
88099eae0e | ||
|
8679713dea | ||
|
a589e4f688 | ||
|
f3021e4d71 | ||
|
c577073f57 | ||
|
e746b4c3e9 | ||
|
16946592b7 | ||
|
f3c8038c42 | ||
|
4637f3ed23 | ||
|
dc32f7eeb1 | ||
|
e997a194a4 | ||
|
e8aa2e6de9 | ||
|
29aa9546a8 | ||
|
17d71b413f | ||
|
3db8e91b51 | ||
|
1b4efa8f4a | ||
|
90d6f0d4e5 | ||
|
dde7db616a | ||
|
30789bcb9b | ||
|
64f71fe453 | ||
|
c1eadce374 | ||
|
73a1160ce3 | ||
|
846699c03c | ||
|
35d8945975 | ||
|
186d98b263 | ||
|
0b7d3846e5 | ||
|
84e0754bd7 | ||
|
c838af6d17 |
@@ -404,12 +404,8 @@ if( WIN32 )
|
||||
endif( WIN32 )
|
||||
|
||||
if( WIN32 OR APPLE )
|
||||
if( TOMAHAWK_QT5 )
|
||||
macro_optional_find_package(LibsnoreQt5 QUIET)
|
||||
else()
|
||||
macro_optional_find_package(Libsnore QUIET)
|
||||
endif()
|
||||
macro_log_feature(LIBSNORE_FOUND "Libsnore" "Library for notifications" "https://github.com/TheOneRing/Snorenotify" FALSE "" "")
|
||||
macro_optional_find_package(LibsnoreQt5 0.5.70 QUIET)
|
||||
macro_log_feature(LibsnoreQt5_FOUND "Libsnore" "Library for notifications" "https://projects.kde.org/projects/playground/libs/snorenotify" FALSE "" "")
|
||||
endif()
|
||||
|
||||
find_package(LIBVLC REQUIRED 2.1.0)
|
||||
|
@@ -6,19 +6,16 @@ find_path(LIBVLC_INCLUDE_DIR vlc/vlc.h
|
||||
HINTS
|
||||
${PC_LIBVLC_INCLUDEDIR}
|
||||
${PC_LIBVLC_INCLUDE_DIRS}
|
||||
/usr/local/opt/vlc/include
|
||||
)
|
||||
|
||||
find_library(LIBVLC_LIBRARY NAMES vlc libvlc
|
||||
HINTS
|
||||
${PC_LIBVLC_LIBDIR}
|
||||
${PC_LIBVLC_LIBRARY_DIRS}
|
||||
/usr/local/opt/vlc/lib
|
||||
)
|
||||
|
||||
find_library(LIBVLCCORE_LIBRARY NAMES vlccore libvlccore
|
||||
HINTS
|
||||
${PC_LIBVLC_LIBDIR}
|
||||
${PC_LIBVLC_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
set(LIBVLC_VERSION ${PC_LIBVLC_VERSION})
|
||||
|
||||
@@ -32,8 +29,6 @@ int main(int argc, char *argv[]) {
|
||||
HAVE_VLC_ALBUMARTIST)
|
||||
|
||||
find_package_handle_standard_args(LibVLC
|
||||
REQUIRED_VARS LIBVLC_LIBRARY LIBVLCCORE_LIBRARY LIBVLC_INCLUDE_DIR
|
||||
REQUIRED_VARS LIBVLC_LIBRARY LIBVLC_INCLUDE_DIR
|
||||
VERSION_VAR LIBVLC_VERSION
|
||||
)
|
||||
|
||||
|
||||
|
@@ -15,21 +15,25 @@
|
||||
;-----------------------------------------------------------------------------
|
||||
; Some paths.
|
||||
;-----------------------------------------------------------------------------
|
||||
!ifndef MING_PATH
|
||||
!define MING_PATH "/usr/i686-w64-mingw32/sys-root/mingw"
|
||||
!ifndef MINGW_ROOT
|
||||
!define MINGW_ROOT "/usr/i686-w64-mingw32/sys-root/mingw"
|
||||
!endif
|
||||
|
||||
!define APPLICATION_NAME "Tomahawk"
|
||||
!define TARGET_NAME "tomahawk"
|
||||
;define app id needed for Windows 8 notifications
|
||||
!define AppUserModelId @TOMAHAWK_APPLICATION_PACKAGE_NAME@
|
||||
|
||||
!define MING_BIN "${MING_PATH}/bin"
|
||||
!define MING_LIB "${MING_PATH}/lib"
|
||||
!define MINGW_BIN "${MINGW_ROOT}/bin"
|
||||
!define MINGW_LIB "${MINGW_ROOT}/lib"
|
||||
!define MINGW_SHARE "${MINGW_ROOT}/share"
|
||||
|
||||
!define BUILD_PATH "@CMAKE_BINARY_DIR@"
|
||||
!define SOURCE_PATH "@CMAKE_SOURCE_DIR@"
|
||||
!define QT_DLL_PATH "${MING_BIN}"
|
||||
!define SQLITE_DLL_PATH "${MING_LIB}/qt5/plugins/sqldrivers"
|
||||
!define IMAGEFORMATS_DLL_PATH "${MING_LIB}/qt5/plugins/imageformats"
|
||||
!define QT_DLL_PATH "${MINGW_BIN}"
|
||||
!define QT_QML_PATH "${MINGW_SHARE}/qt5/qml"
|
||||
!define SQLITE_DLL_PATH "${MINGW_LIB}/qt5/plugins/sqldrivers"
|
||||
!define IMAGEFORMATS_DLL_PATH "${MINGW_LIB}/qt5/plugins/imageformats"
|
||||
|
||||
; We use official release plugins
|
||||
; mingw32-vlc from obs misses a lot and has even broken ones probably
|
||||
@@ -330,7 +334,7 @@ Section "${APPLICATION_NAME}" SEC_TOMAHAWK_PLAYER
|
||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Multimedia.dll"
|
||||
File "${QT_DLL_PATH}\Qt5MultimediaWidgets.dll"
|
||||
|
||||
File "${QT_DLL_PATH}\Qt5Positioning.dll"
|
||||
|
||||
;Qt deps
|
||||
File "${QT_DLL_PATH}\libpcre16-0.dll"
|
||||
@@ -339,21 +343,19 @@ Section "${APPLICATION_NAME}" SEC_TOMAHAWK_PLAYER
|
||||
File "${QT_DLL_PATH}\libEGL.dll"
|
||||
File "${QT_DLL_PATH}\libGLESv2.dll"
|
||||
File "${QT_DLL_PATH}\libwebp-5.dll"
|
||||
|
||||
;Boost fnord
|
||||
File "${QT_DLL_PATH}\icuuc53.dll"
|
||||
File "${QT_DLL_PATH}\icudata53.dll"
|
||||
File "${QT_DLL_PATH}\icui18n53.dll"
|
||||
File "${QT_DLL_PATH}\icuuc56.dll"
|
||||
File "${QT_DLL_PATH}\icudata56.dll"
|
||||
File "${QT_DLL_PATH}\icui18n56.dll"
|
||||
|
||||
;SQLite driver
|
||||
SetOutPath "$INSTDIR\sqldrivers"
|
||||
File "${SQLITE_DLL_PATH}\qsqlite.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MINGW_BIN}\libsqlite3-0.dll"
|
||||
|
||||
;Qt platform plugins
|
||||
SetOutPath "$INSTDIR\platforms"
|
||||
File "${MING_LIB}/qt5/plugins/platforms/qwindows.dll"
|
||||
File "${MINGW_LIB}/qt5/plugins/platforms/qwindows.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
;Image plugins
|
||||
@@ -363,9 +365,16 @@ Section "${APPLICATION_NAME}" SEC_TOMAHAWK_PLAYER
|
||||
File "${IMAGEFORMATS_DLL_PATH}\qsvg.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
;Qt qml plugins
|
||||
SetOutPath "$INSTDIR\QtQuick.2"
|
||||
File /r /x *.debug "${QT_QML_PATH}\QtQuick.2\*"
|
||||
SetOutPath "$INSTDIR\QtQuick\Window.2"
|
||||
File /r /x *.debug "${QT_QML_PATH}\QtQuick\Window.2\*"
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
;Cygwin/c++ stuff
|
||||
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MINGW_BIN}\libgcc_s_sjlj-1.dll"
|
||||
File "${MINGW_BIN}\libstdc++-6.dll"
|
||||
|
||||
;VLC
|
||||
File "${VLC_BIN}\libvlc.dll"
|
||||
@@ -375,60 +384,68 @@ Section "${APPLICATION_NAME}" SEC_TOMAHAWK_PLAYER
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
; Other
|
||||
File "${MING_BIN}\libtag.dll"
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
File "${MING_BIN}\zlib1.dll"
|
||||
File "${MINGW_BIN}\libtag.dll"
|
||||
File "${MINGW_BIN}\libpng16-16.dll"
|
||||
File "${MINGW_BIN}\libjpeg-8.dll"
|
||||
File "${MINGW_BIN}\zlib1.dll"
|
||||
File "${MINGW_BIN}\libfreetype-6.dll"
|
||||
File "${MINGW_BIN}\libglib-2.0-0.dll"
|
||||
File "${MINGW_BIN}\libharfbuzz-0.dll"
|
||||
|
||||
File "${MING_BIN}\libechonest5.dll"
|
||||
File "${MING_BIN}\liblastfm5.dll"
|
||||
File "${MING_BIN}\libquazip5.dll"
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
File "${MINGW_BIN}\libechonest5.dll"
|
||||
File "${MINGW_BIN}\liblastfm5.dll"
|
||||
File "${MINGW_BIN}\libquazip5.dll"
|
||||
File "${MINGW_BIN}\libqt5keychain.dll"
|
||||
|
||||
; GnuTLS
|
||||
File "${MING_BIN}\libgnutls-28.dll"
|
||||
File "${MING_BIN}\libtasn1-6.dll"
|
||||
File "${MING_BIN}\libgmp-10.dll"
|
||||
File "${MING_BIN}\libhogweed-2-4.dll"
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
File "${MING_BIN}\libnettle-4-6.dll"
|
||||
File "${MING_BIN}\libp11-kit-0.dll"
|
||||
File "${MING_BIN}\libffi-6.dll"
|
||||
File "${MINGW_BIN}\libgnutls-28.dll"
|
||||
File "${MINGW_BIN}\libtasn1-6.dll"
|
||||
File "${MINGW_BIN}\libgmp-10.dll"
|
||||
File "${MINGW_BIN}\libhogweed-2-4.dll"
|
||||
File "${MINGW_BIN}\libintl-8.dll"
|
||||
File "${MINGW_BIN}\libnettle-4-6.dll"
|
||||
File "${MINGW_BIN}\libp11-kit-0.dll"
|
||||
File "${MINGW_BIN}\libffi-6.dll"
|
||||
|
||||
; Snorenotify
|
||||
File "${MING_BIN}\SnoreToast.exe"
|
||||
File "${MING_BIN}\libsnore-qt5.dll"
|
||||
File "${MING_LIB}\plugins\libsnore-qt5\libsnore_backend_growl.dll"
|
||||
File "${MING_LIB}\plugins\libsnore-qt5\libsnore_backend_snarl.dll"
|
||||
File "${MING_LIB}\plugins\libsnore-qt5\libsnore_backend_snore.dll"
|
||||
File "${MING_LIB}\plugins\libsnore-qt5\libsnore_backend_snoretoast.dll"
|
||||
File "${MINGW_BIN}\SnoreToast.exe"
|
||||
File "${MINGW_BIN}\libsnore-qt5.dll"
|
||||
File "${MINGW_BIN}\libsnoresettings-qt5.dll"
|
||||
File "${MINGW_BIN}\snoresettings.exe"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_backend_growl.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_settings_backend_growl.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_backend_snarl.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_settings_backend_snarl.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_backend_snore.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_settings_backend_snore.dll"
|
||||
File "${MINGW_LIB}\plugins\libsnore-qt5\libsnore_backend_windowstoast.dll"
|
||||
|
||||
; Snoregrowl
|
||||
File "${MING_BIN}\libsnoregrowl++.dll"
|
||||
File "${MING_BIN}\libsnoregrowl.dll"
|
||||
File "${MINGW_BIN}\libsnoregrowl++.dll"
|
||||
File "${MINGW_BIN}\libsnoregrowl.dll"
|
||||
|
||||
; Jabber
|
||||
File "${MING_BIN}\libjreen-qt5.dll"
|
||||
File "${MING_BIN}\libidn-11.dll"
|
||||
File "${MING_BIN}\libgsasl-7.dll"
|
||||
File "${MING_BIN}\libqca-qt5.dll"
|
||||
File "${MINGW_BIN}\libjreen-qt5.dll"
|
||||
File "${MINGW_BIN}\libidn-11.dll"
|
||||
File "${MINGW_BIN}\libgsasl-7.dll"
|
||||
File "${MINGW_BIN}\libqca-qt5.dll"
|
||||
SetOutPath "$INSTDIR\crypto"
|
||||
File "${MING_LIB}\qca-qt5\crypto\libqca-ossl.dll"
|
||||
File "${MINGW_LIB}\qca-qt5\crypto\libqca-ossl.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MINGW_BIN}\libssl-10.dll"
|
||||
File "${MINGW_BIN}\libcrypto-10.dll"
|
||||
|
||||
; LucenePlusPlus
|
||||
File "${MING_BIN}\liblucene++.dll"
|
||||
File "${MING_BIN}\libboost_system-mt.dll"
|
||||
File "${MING_BIN}\libboost_filesystem-mt.dll"
|
||||
File "${MING_BIN}\libboost_iostreams-mt.dll"
|
||||
File "${MING_BIN}\libboost_regex-mt.dll"
|
||||
File "${MING_BIN}\libboost_thread-mt.dll"
|
||||
File "${MING_BIN}\libbz2-1.dll"
|
||||
File "${MINGW_BIN}\liblucene++.dll"
|
||||
File "${MINGW_BIN}\libboost_system-mt.dll"
|
||||
File "${MINGW_BIN}\libboost_filesystem-mt.dll"
|
||||
File "${MINGW_BIN}\libboost_iostreams-mt.dll"
|
||||
File "${MINGW_BIN}\libboost_regex-mt.dll"
|
||||
File "${MINGW_BIN}\libboost_thread-mt.dll"
|
||||
File "${MINGW_BIN}\libbz2-1.dll"
|
||||
|
||||
File "${MING_BIN}\libqtsparkle-qt5.dll"
|
||||
File "${MING_BIN}\libKF5Attica.dll"
|
||||
File "${MINGW_BIN}\libqtsparkle-qt5.dll"
|
||||
File "${MINGW_BIN}\libKF5Attica.dll"
|
||||
SectionEnd
|
||||
|
||||
SectionGroup "Shortcuts"
|
||||
@@ -443,7 +460,7 @@ SectionGroup "Shortcuts"
|
||||
RMDir /r "$SMPROGRAMS\${APPLICATION_NAME}"
|
||||
CreateDirectory "$SMPROGRAMS\${APPLICATION_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\LICENSE.lnk" "$INSTDIR\LICENSE.txt"
|
||||
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_NAME}.exe"
|
||||
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Notification Settings.lnk" "$INSTDIR\snoresettings.exe" "-a ${APPLICATION_NAME}"
|
||||
!insertmacro SnoreShortcut "$SMPROGRAMS\${APPLICATION_NAME}\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_NAME}.exe" "${AppUserModelId}"
|
||||
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Release notes.lnk" "$INSTDIR\NOTES.txt"
|
||||
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
@@ -5,23 +5,23 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Tomahawk</string>
|
||||
<string>@TOMAHAWK_APPLICATION_NAME@</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.tomahawk-player.Tomahawk</string>
|
||||
<string>@TOMAHAWK_APPLICATION_PACKAGE_NAME@</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>TOMAHAWK_VERSION</string>
|
||||
<string>@TOMAHAWK_VERSION@</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>TOMAHAWK_VERSION</string>
|
||||
<string>@TOMAHAWK_VERSION@</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>tomahawk</string>
|
||||
<string>@TOMAHAWK_BASE_TARGET_NAME@</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Tomahawk.icns</string>
|
||||
<string>@TOMAHAWK_APPLICATION_NAME@.icns</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Tomahawk</string>
|
||||
<string>@TOMAHAWK_APPLICATION_NAME@</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
@@ -29,7 +29,7 @@
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true />
|
||||
<key>SUFeedURL</key>
|
||||
<string>http://download.tomahawk-player.org/sparkle/update.php</string>
|
||||
<string>@TOMAHAWK_SPARKLE_UPDATE_URL@</string>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
<string>sparkle_pub.pem</string>
|
||||
<key>SUEnableSystemProfiling</key>
|
||||
|
@@ -4,8 +4,9 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
TARGET_NAME="Tomahawk"
|
||||
|
||||
set -e
|
||||
|
||||
function header {
|
||||
echo -e "\033[0;34m==>\033[0;0;1m $1 \033[0;0m"
|
||||
@@ -31,30 +32,28 @@ CERT_SIGNER=$2
|
||||
################################################################################
|
||||
|
||||
header "Fixing and copying libraries"
|
||||
$ROOT/../admin/mac/macdeploy.py Tomahawk.app quiet
|
||||
$ROOT/../admin/mac/macdeploy.py "${TARGET_NAME}.app" quiet
|
||||
|
||||
cd Tomahawk.app
|
||||
cd "${TARGET_NAME}.app"
|
||||
|
||||
cp $ROOT/../admin/mac/qt.conf Contents/Resources/qt.conf
|
||||
|
||||
# header "Copying Sparkle framework"
|
||||
# cp -R /Library/Frameworks/Sparkle.framework Contents/Frameworks
|
||||
|
||||
header "Creating DMG"
|
||||
cd ..
|
||||
header "Fixing fonts"
|
||||
mkdir "${ROOT}/${TARGET_NAME}.app/Contents/Resources/Fonts"
|
||||
cp -R $ROOT/../data/fonts/*.ttf "${ROOT}/${TARGET_NAME}.app/Contents/Resources/Fonts"
|
||||
|
||||
header "Signing bundle"
|
||||
# codesign -s "Developer ID Application: $CERT_SIGNER" -f -v ./Tomahawk.app
|
||||
|
||||
cd ..
|
||||
if [ -f ~/sign_step.sh ];
|
||||
then
|
||||
~/sign_step.sh "$CERT_SIGNER" "Tomahawk.app" || true
|
||||
~/sign_step.sh "$CERT_SIGNER" "${TARGET_NAME}.app" || true
|
||||
fi
|
||||
|
||||
$ROOT/../admin/mac/create-dmg.sh Tomahawk.app
|
||||
mv Tomahawk.dmg Tomahawk-$VERSION.dmg
|
||||
header "Creating DMG"
|
||||
$ROOT/../admin/mac/create-dmg.sh "${TARGET_NAME}.app"
|
||||
mv "${TARGET_NAME}.dmg" "${TARGET_NAME}-$VERSION.dmg"
|
||||
|
||||
header "Creating signed Sparkle update"
|
||||
$ROOT/../admin/mac/sign_bundle.rb $VERSION ~/tomahawk_sparkle_privkey.pem
|
||||
# $ROOT/../admin/mac/sign_bundle.rb "${TARGET_NAME}" $VERSION ~/tomahawk_sparkle_privkey.pem
|
||||
|
||||
header "Done!"
|
||||
|
@@ -43,7 +43,7 @@ ln -s /Applications "$TMP/Applications"
|
||||
cp -R "$IN" "$TMP"
|
||||
|
||||
# create
|
||||
hdiutil makehybrid -hfs -hfs-volume-name Tomahawk -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg
|
||||
hdiutil makehybrid -hfs -hfs-volume-name "$NAME" -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg
|
||||
hdiutil convert -format UDZO -imagekey zlib-level=9 tmp.dmg -o "$OUT"
|
||||
|
||||
# cleanup
|
||||
|
@@ -22,171 +22,170 @@ import commands
|
||||
import sys
|
||||
import glob
|
||||
|
||||
TARGET_NAME="tomahawk"
|
||||
|
||||
FRAMEWORK_SEARCH_PATH=[
|
||||
'/Library/Frameworks',
|
||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||
]
|
||||
|
||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.19.2/lib', '.']
|
||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/opt/vlc/lib', '/usr/local/Cellar/gettext/0.19.2/lib', '.']
|
||||
|
||||
VLC_PLUGINS=[
|
||||
'access/libattachment_plugin.dylib',
|
||||
#'access/libaccess_avio_plugin.dylib',
|
||||
#'access/libaccess_fake_plugin.dylib',
|
||||
'access/libftp_plugin.dylib',
|
||||
'access/libhttp_plugin.dylib',
|
||||
'access/libimem_plugin.dylib',
|
||||
#'access/libaccess_mmap_plugin.dylib',
|
||||
'access/libaccess_mms_plugin.dylib',
|
||||
'access/libaccess_realrtsp_plugin.dylib',
|
||||
'access/libtcp_plugin.dylib',
|
||||
'access/libudp_plugin.dylib',
|
||||
'access/libcdda_plugin.dylib',
|
||||
'access/libfilesystem_plugin.dylib',
|
||||
'access/libqtcapture_plugin.dylib',
|
||||
'access/librtp_plugin.dylib',
|
||||
'access/libzip_plugin.dylib',
|
||||
'access_output/libaccess_output_dummy_plugin.dylib',
|
||||
'access_output/libaccess_output_file_plugin.dylib',
|
||||
'access_output/libaccess_output_http_plugin.dylib',
|
||||
'access_output/libaccess_output_shout_plugin.dylib',
|
||||
'access_output/libaccess_output_udp_plugin.dylib',
|
||||
'audio_filter/liba52tofloat32_plugin.dylib',
|
||||
'audio_filter/liba52tospdif_plugin.dylib',
|
||||
'audio_filter/libaudio_format_plugin.dylib',
|
||||
'audio_filter/libaudiobargraph_a_plugin.dylib',
|
||||
'audio_filter/libchorus_flanger_plugin.dylib',
|
||||
'libattachment_plugin.dylib',
|
||||
#'libaccess_avio_plugin.dylib',
|
||||
#'libaccess_fake_plugin.dylib',
|
||||
'libftp_plugin.dylib',
|
||||
'libhttp_plugin.dylib',
|
||||
'libhttplive_plugin.dylib',
|
||||
'libimem_plugin.dylib',
|
||||
#'libaccess_mmap_plugin.dylib',
|
||||
'libaccess_mms_plugin.dylib',
|
||||
'libaccess_realrtsp_plugin.dylib',
|
||||
'libtcp_plugin.dylib',
|
||||
'libudp_plugin.dylib',
|
||||
'libcdda_plugin.dylib',
|
||||
'libfilesystem_plugin.dylib',
|
||||
'libqtcapture_plugin.dylib',
|
||||
'librtp_plugin.dylib',
|
||||
'libzip_plugin.dylib',
|
||||
'liba52tofloat32_plugin.dylib',
|
||||
'liba52tospdif_plugin.dylib',
|
||||
'libaudio_format_plugin.dylib',
|
||||
'libaudiobargraph_a_plugin.dylib',
|
||||
'libchorus_flanger_plugin.dylib',
|
||||
#'libconverter_fixed_plugin.dylib',
|
||||
'audio_filter/libdolby_surround_decoder_plugin.dylib',
|
||||
'audio_filter/libdtstofloat32_plugin.dylib',
|
||||
'audio_filter/libdtstospdif_plugin.dylib',
|
||||
'audio_filter/libequalizer_plugin.dylib',
|
||||
'audio_filter/libheadphone_channel_mixer_plugin.dylib',
|
||||
'audio_filter/libmono_plugin.dylib',
|
||||
'audio_filter/libmpgatofixed32_plugin.dylib',
|
||||
'audio_filter/libnormvol_plugin.dylib',
|
||||
'audio_filter/libparam_eq_plugin.dylib',
|
||||
'audio_filter/libscaletempo_plugin.dylib',
|
||||
'audio_filter/libsimple_channel_mixer_plugin.dylib',
|
||||
'audio_filter/libspatializer_plugin.dylib',
|
||||
'audio_filter/libtrivial_channel_mixer_plugin.dylib',
|
||||
'audio_filter/libugly_resampler_plugin.dylib',
|
||||
'audio_mixer/libfloat_mixer_plugin.dylib',
|
||||
'libdolby_surround_decoder_plugin.dylib',
|
||||
'libdtstofloat32_plugin.dylib',
|
||||
'libdtstospdif_plugin.dylib',
|
||||
'libequalizer_plugin.dylib',
|
||||
'libheadphone_channel_mixer_plugin.dylib',
|
||||
'libmono_plugin.dylib',
|
||||
'libmpgatofixed32_plugin.dylib',
|
||||
'libnormvol_plugin.dylib',
|
||||
'libparam_eq_plugin.dylib',
|
||||
'libscaletempo_plugin.dylib',
|
||||
'libsimple_channel_mixer_plugin.dylib',
|
||||
'libspatializer_plugin.dylib',
|
||||
'libtrivial_channel_mixer_plugin.dylib',
|
||||
'libugly_resampler_plugin.dylib',
|
||||
'libfloat_mixer_plugin.dylib',
|
||||
#'libspdif_mixer_plugin.dylib',
|
||||
#'libtrivial_mixer_plugin.dylib',
|
||||
#'libaout_file_plugin.dylib',
|
||||
'audio_output/libauhal_plugin.dylib',
|
||||
'codec/liba52_plugin.dylib',
|
||||
'codec/libadpcm_plugin.dylib',
|
||||
'codec/libaes3_plugin.dylib',
|
||||
'codec/libaraw_plugin.dylib',
|
||||
'codec/libavcodec_plugin.dylib',
|
||||
'codec/libcc_plugin.dylib',
|
||||
'codec/libcdg_plugin.dylib',
|
||||
'codec/libdts_plugin.dylib',
|
||||
'codec/libfaad_plugin.dylib',
|
||||
'libauhal_plugin.dylib',
|
||||
'liba52_plugin.dylib',
|
||||
'libadpcm_plugin.dylib',
|
||||
'libaes3_plugin.dylib',
|
||||
'libaraw_plugin.dylib',
|
||||
'libavcodec_plugin.dylib',
|
||||
'libcc_plugin.dylib',
|
||||
'libcdg_plugin.dylib',
|
||||
'libdts_plugin.dylib',
|
||||
'libfaad_plugin.dylib',
|
||||
#'libfake_plugin.dylib',
|
||||
'codec/libflac_plugin.dylib',
|
||||
'libflac_plugin.dylib',
|
||||
#'libfluidsynth_plugin.dylib',
|
||||
#'libinvmem_plugin.dylib',
|
||||
'codec/liblpcm_plugin.dylib',
|
||||
'codec/libmpeg_audio_plugin.dylib',
|
||||
'codec/libpng_plugin.dylib',
|
||||
'codec/librawvideo_plugin.dylib',
|
||||
'codec/libspeex_plugin.dylib',
|
||||
'codec/libspudec_plugin.dylib',
|
||||
'codec/libtheora_plugin.dylib',
|
||||
'codec/libtwolame_plugin.dylib',
|
||||
'codec/libvorbis_plugin.dylib',
|
||||
#'control/libgestures_plugin.dylib',
|
||||
'liblpcm_plugin.dylib',
|
||||
'libmpeg_audio_plugin.dylib',
|
||||
'libpng_plugin.dylib',
|
||||
'librawvideo_plugin.dylib',
|
||||
'libspeex_plugin.dylib',
|
||||
'libspudec_plugin.dylib',
|
||||
'libtheora_plugin.dylib',
|
||||
'libtwolame_plugin.dylib',
|
||||
'libvorbis_plugin.dylib',
|
||||
#'libgestures_plugin.dylib',
|
||||
#'libhotkeys_plugin.dylib',
|
||||
#'libmotion_plugin.dylib',
|
||||
#'libnetsync_plugin.dylib',
|
||||
#'libsignals_plugin.dylib',
|
||||
'demux/libaiff_plugin.dylib',
|
||||
'demux/libasf_plugin.dylib',
|
||||
'demux/libau_plugin.dylib',
|
||||
'libaiff_plugin.dylib',
|
||||
'libasf_plugin.dylib',
|
||||
'libau_plugin.dylib',
|
||||
#'libavformat_plugin.dylib',
|
||||
'demux/libavi_plugin.dylib',
|
||||
'demux/libdemux_cdg_plugin.dylib',
|
||||
'demux/libdemuxdump_plugin.dylib',
|
||||
'demux/libdiracsys_plugin.dylib',
|
||||
'demux/libes_plugin.dylib',
|
||||
'demux/libflacsys_plugin.dylib',
|
||||
'access/liblive555_plugin.dylib',
|
||||
'demux/libmkv_plugin.dylib',
|
||||
'demux/libmod_plugin.dylib',
|
||||
'demux/libmp4_plugin.dylib',
|
||||
'demux/libmpc_plugin.dylib',
|
||||
'demux/libmpgv_plugin.dylib',
|
||||
'demux/libnsc_plugin.dylib',
|
||||
'demux/libnsv_plugin.dylib',
|
||||
'demux/libnuv_plugin.dylib',
|
||||
'demux/libogg_plugin.dylib',
|
||||
'demux/libplaylist_plugin.dylib',
|
||||
'demux/libps_plugin.dylib',
|
||||
'demux/libpva_plugin.dylib',
|
||||
'demux/librawaud_plugin.dylib',
|
||||
'demux/librawdv_plugin.dylib',
|
||||
'demux/librawvid_plugin.dylib',
|
||||
'demux/libreal_plugin.dylib',
|
||||
'demux/libsmf_plugin.dylib',
|
||||
'demux/libts_plugin.dylib',
|
||||
'demux/libtta_plugin.dylib',
|
||||
'demux/libty_plugin.dylib',
|
||||
'demux/libvc1_plugin.dylib',
|
||||
'demux/libvoc_plugin.dylib',
|
||||
'demux/libwav_plugin.dylib',
|
||||
'demux/libxa_plugin.dylib',
|
||||
'meta_engine/libfolder_plugin.dylib',
|
||||
'meta_engine/libtaglib_plugin.dylib',
|
||||
'libavi_plugin.dylib',
|
||||
'libdemux_cdg_plugin.dylib',
|
||||
'libdemuxdump_plugin.dylib',
|
||||
'libdiracsys_plugin.dylib',
|
||||
'libes_plugin.dylib',
|
||||
'libflacsys_plugin.dylib',
|
||||
'liblive555_plugin.dylib',
|
||||
'libmkv_plugin.dylib',
|
||||
'libmod_plugin.dylib',
|
||||
'libmp4_plugin.dylib',
|
||||
'libmpc_plugin.dylib',
|
||||
'libmpgv_plugin.dylib',
|
||||
'libnsc_plugin.dylib',
|
||||
'libnsv_plugin.dylib',
|
||||
'libnuv_plugin.dylib',
|
||||
'libogg_plugin.dylib',
|
||||
'libplaylist_plugin.dylib',
|
||||
'libps_plugin.dylib',
|
||||
'libpva_plugin.dylib',
|
||||
'librawaud_plugin.dylib',
|
||||
'librawdv_plugin.dylib',
|
||||
'librawvid_plugin.dylib',
|
||||
'libreal_plugin.dylib',
|
||||
'libsmf_plugin.dylib',
|
||||
'libts_plugin.dylib',
|
||||
'libtta_plugin.dylib',
|
||||
'libty_plugin.dylib',
|
||||
'libvc1_plugin.dylib',
|
||||
'libvoc_plugin.dylib',
|
||||
'libwav_plugin.dylib',
|
||||
'libxa_plugin.dylib',
|
||||
'libfolder_plugin.dylib',
|
||||
'libtaglib_plugin.dylib',
|
||||
#'libaudioscrobbler_plugin.dylib',
|
||||
'control/libdummy_plugin.dylib',
|
||||
'misc/libexport_plugin.dylib',
|
||||
'libdummy_plugin.dylib',
|
||||
'libexport_plugin.dylib',
|
||||
#'libfreetype_plugin.dylib',
|
||||
#'libgnutls_plugin.dylib',
|
||||
'misc/liblogger_plugin.dylib',
|
||||
'lua/liblua_plugin.dylib',
|
||||
'liblogger_plugin.dylib',
|
||||
'liblua_plugin.dylib',
|
||||
#'libosd_parser_plugin.dylib',
|
||||
#'libquartztext_plugin.dylib',
|
||||
#'libstats_plugin.dylib',
|
||||
'misc/libvod_rtsp_plugin.dylib',
|
||||
'misc/libxml_plugin.dylib',
|
||||
'libvod_rtsp_plugin.dylib',
|
||||
'libxml_plugin.dylib',
|
||||
#'libxtag_plugin.dylib',
|
||||
'video_chroma/libi420_rgb_mmx_plugin.dylib',
|
||||
'video_chroma/libi420_yuy2_mmx_plugin.dylib',
|
||||
'video_chroma/libi422_yuy2_mmx_plugin.dylib',
|
||||
'libi420_rgb_mmx_plugin.dylib',
|
||||
'libi420_yuy2_mmx_plugin.dylib',
|
||||
'libi422_yuy2_mmx_plugin.dylib',
|
||||
#'libmemcpymmx_plugin.dylib',
|
||||
#'libmemcpymmxext_plugin.dylib',
|
||||
'mux/libmux_asf_plugin.dylib',
|
||||
'mux/libmux_avi_plugin.dylib',
|
||||
'mux/libmux_dummy_plugin.dylib',
|
||||
'mux/libmux_mp4_plugin.dylib',
|
||||
'mux/libmux_mpjpeg_plugin.dylib',
|
||||
'mux/libmux_ogg_plugin.dylib',
|
||||
'mux/libmux_ps_plugin.dylib',
|
||||
'mux/libmux_ts_plugin.dylib',
|
||||
'mux/libmux_wav_plugin.dylib',
|
||||
'packetizer/libpacketizer_copy_plugin.dylib',
|
||||
'packetizer/libpacketizer_dirac_plugin.dylib',
|
||||
'packetizer/libpacketizer_flac_plugin.dylib',
|
||||
'packetizer/libpacketizer_h264_plugin.dylib',
|
||||
'packetizer/libpacketizer_mlp_plugin.dylib',
|
||||
'packetizer/libpacketizer_mpeg4audio_plugin.dylib',
|
||||
'packetizer/libpacketizer_mpeg4video_plugin.dylib',
|
||||
'packetizer/libpacketizer_mpegvideo_plugin.dylib',
|
||||
'packetizer/libpacketizer_vc1_plugin.dylib',
|
||||
'video_chroma/libi420_rgb_sse2_plugin.dylib',
|
||||
'video_chroma/libi420_yuy2_sse2_plugin.dylib',
|
||||
'video_chroma/libi422_yuy2_sse2_plugin.dylib',
|
||||
'stream_filter/libdecomp_plugin.dylib',
|
||||
#'access/libstream_filter_rar_plugin.dylib',
|
||||
'stream_filter/librecord_plugin.dylib',
|
||||
'libmux_asf_plugin.dylib',
|
||||
'libmux_avi_plugin.dylib',
|
||||
'libmux_dummy_plugin.dylib',
|
||||
'libmux_mp4_plugin.dylib',
|
||||
'libmux_mpjpeg_plugin.dylib',
|
||||
'libmux_ogg_plugin.dylib',
|
||||
'libmux_ps_plugin.dylib',
|
||||
'libmux_ts_plugin.dylib',
|
||||
'libmux_wav_plugin.dylib',
|
||||
'libpacketizer_copy_plugin.dylib',
|
||||
'libpacketizer_dirac_plugin.dylib',
|
||||
'libpacketizer_flac_plugin.dylib',
|
||||
'libpacketizer_h264_plugin.dylib',
|
||||
'libpacketizer_mlp_plugin.dylib',
|
||||
'libpacketizer_mpeg4audio_plugin.dylib',
|
||||
'libpacketizer_mpeg4video_plugin.dylib',
|
||||
'libpacketizer_mpegvideo_plugin.dylib',
|
||||
'libpacketizer_vc1_plugin.dylib',
|
||||
'libi420_rgb_sse2_plugin.dylib',
|
||||
'libi420_yuy2_sse2_plugin.dylib',
|
||||
'libi422_yuy2_sse2_plugin.dylib',
|
||||
'libdecomp_plugin.dylib',
|
||||
#'libstream_filter_rar_plugin.dylib',
|
||||
'librecord_plugin.dylib',
|
||||
#'libvisual_plugin.dylib',
|
||||
'libsecuretransport_plugin.dylib'
|
||||
]
|
||||
|
||||
VLC_SEARCH_PATH=[
|
||||
'/usr/local/lib/vlc/plugins/',
|
||||
'/usr/local/opt/vlc/lib/vlc/plugins/',
|
||||
]
|
||||
|
||||
QT_PLUGINS = [
|
||||
@@ -201,39 +200,39 @@ QT_PLUGINS = [
|
||||
]
|
||||
|
||||
SNORE_PLUGINS = [
|
||||
# 'libsnore_backend_growl.so',
|
||||
# 'libsnore_backend_osxnotificationcenter.so',
|
||||
'libsnore_backend_growl.so',
|
||||
'libsnore_backend_osxnotificationcenter.so',
|
||||
]
|
||||
|
||||
TOMAHAWK_PLUGINS = [
|
||||
'libtomahawk_account_xmpp.dylib',
|
||||
'libtomahawk_account_google.so',
|
||||
'libtomahawk_account_zeroconf.so',
|
||||
# 'libtomahawk_account_hatchet.so',
|
||||
'libtomahawk_infoplugin_adium.so',
|
||||
'libtomahawk_infoplugin_charts.so',
|
||||
'libtomahawk_infoplugin_discogs.so',
|
||||
'libtomahawk_infoplugin_echonest.so',
|
||||
'libtomahawk_infoplugin_hypem.so',
|
||||
'libtomahawk_infoplugin_musicbrainz.so',
|
||||
'libtomahawk_infoplugin_musixmatch.so',
|
||||
'libtomahawk_infoplugin_newreleases.so',
|
||||
'libtomahawk_infoplugin_rovi.so',
|
||||
# 'libtomahawk_infoplugin_snorenotify.so',
|
||||
'libtomahawk_infoplugin_spotify.so',
|
||||
'libtomahawk_viewpage_dashboard.so',
|
||||
# 'libtomahawk_viewpage_networkactivity.so',
|
||||
'libtomahawk_viewpage_charts.so',
|
||||
'libtomahawk_viewpage_newreleases.so',
|
||||
'libtomahawk_viewpage_whatsnew_0_8.so',
|
||||
'lib%s_account_xmpp.dylib' % TARGET_NAME,
|
||||
'lib%s_account_google.so' % TARGET_NAME,
|
||||
'lib%s_account_zeroconf.so' % TARGET_NAME,
|
||||
'lib%s_account_hatchet.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_adium.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_charts.so' % TARGET_NAME,
|
||||
# 'lib%s_infoplugin_discogs.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_echonest.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_hypem.so' % TARGET_NAME,
|
||||
# 'lib%s_infoplugin_musicbrainz.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_musixmatch.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_newreleases.so' % TARGET_NAME,
|
||||
# 'lib%s_infoplugin_rovi.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_snorenotify.so' % TARGET_NAME,
|
||||
'lib%s_infoplugin_spotify.so' % TARGET_NAME,
|
||||
'lib%s_viewpage_dashboard.so' % TARGET_NAME,
|
||||
# 'lib%s_viewpage_networkactivity.so' % TARGET_NAME,
|
||||
'lib%s_viewpage_charts.so' % TARGET_NAME,
|
||||
'lib%s_viewpage_newreleases.so' % TARGET_NAME,
|
||||
'lib%s_viewpage_whatsnew_0_8.so' % TARGET_NAME,
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
'/usr/local/Cellar/qt5/5.4.0/plugins',
|
||||
'/usr/local/opt/qt5/plugins',
|
||||
]
|
||||
|
||||
SNORE_PLUGINS_SEARCH_PATH=[
|
||||
'/usr/local/Cellar/snorenotify/HEAD/lib/libsnore',
|
||||
'/usr/local/opt/snorenotify/lib/plugins/libsnore-qt5',
|
||||
]
|
||||
|
||||
class Error(Exception):
|
||||
@@ -247,6 +246,8 @@ class CouldNotFindQtPluginErrorFindFrameworkError(Error):
|
||||
class InstallNameToolError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindFrameworkError(Error):
|
||||
pass
|
||||
|
||||
class CouldNotFindQtPluginError(Error):
|
||||
pass
|
||||
@@ -308,7 +309,7 @@ def GetBrokenLibraries(binary):
|
||||
continue # unix style system library
|
||||
elif re.match(r'Breakpad', line):
|
||||
continue # Manually added by cmake.
|
||||
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
|
||||
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line) and not re.match(r'^\s*@loader_path/../lib', line):
|
||||
# Potentially already fixed library
|
||||
if '.framework' in line:
|
||||
relative_path = os.path.join(*line.split('/')[3:])
|
||||
@@ -332,6 +333,11 @@ def FindFramework(path):
|
||||
if os.path.exists(abs_path):
|
||||
return abs_path
|
||||
|
||||
# replace rpath with /Library/Frameworks for Sparkle
|
||||
abs_path = path.replace("@rpath/", "/Library/Frameworks/")
|
||||
if os.path.exists(abs_path):
|
||||
return abs_path
|
||||
|
||||
raise CouldNotFindFrameworkError(path)
|
||||
|
||||
def FindLibrary(path):
|
||||
@@ -576,12 +582,12 @@ for plugin in TOMAHAWK_PLUGINS:
|
||||
FixPlugin(plugin, '../MacOS')
|
||||
|
||||
for plugin in SNORE_PLUGINS:
|
||||
FixPlugin(FindSnorePlugin(plugin), '../MacOS/libsnore')
|
||||
FixPlugin(FindSnorePlugin(plugin), '../lib/plugins/libsnore-qt5')
|
||||
|
||||
try:
|
||||
FixPlugin('tomahawk_crash_reporter', '../MacOS')
|
||||
FixPlugin('%s_crash_reporter' % TARGET_NAME, '../MacOS')
|
||||
except:
|
||||
print 'Failed to find tomahawk_crash_reporter'
|
||||
print 'Failed to find %s_crash_reporter' % TARGET_NAME
|
||||
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
@@ -6,9 +6,9 @@ if ARGV.length < 2
|
||||
exit
|
||||
end
|
||||
|
||||
tarball = "tomahawk-#{ARGV[0]}.tar.bz2"
|
||||
tarball = "#{ARGV[0].downcase}-#{ARGV[1]}.tar.bz2"
|
||||
puts "Zipping: #{tarball}..."
|
||||
`tar jcvf "#{tarball}" Tomahawk.app`
|
||||
`tar jcvf "#{tarball}" #{ARGV[0]}.app`
|
||||
|
||||
puts "Signing..."
|
||||
puts `openssl dgst -sha1 -binary < "#{tarball}" | openssl dgst -dss1 -sign "#{ARGV[1]}" | openssl enc -base64`
|
||||
puts `openssl dgst -sha1 -binary < "#{tarball}" | openssl dgst -dss1 -sign "#{ARGV[2]}" | openssl enc -base64`
|
||||
|
55
data/images/nav-back.svg
Normal file
55
data/images/nav-back.svg
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<title>nav-back</title>
|
||||
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="nav-back" sketch:type="MSLayerGroup" transform="translate(4.000000, 6.000000)">
|
||||
<g id="Layer_2"></g>
|
||||
<g id="Layer_3"></g>
|
||||
<g id="Layer_4"></g>
|
||||
<g id="Layer_5"></g>
|
||||
<g id="Layer_6"></g>
|
||||
<g id="Layer_8"></g>
|
||||
<g id="Layer_9"></g>
|
||||
<g id="Layer_10"></g>
|
||||
<g id="Layer_11"></g>
|
||||
<g id="Layer_12"></g>
|
||||
<g id="Layer_13"></g>
|
||||
<g id="Layer_14"></g>
|
||||
<g id="Layer_15"></g>
|
||||
<g id="Layer_16"></g>
|
||||
<g id="Layer_17"></g>
|
||||
<g id="Layer_18"></g>
|
||||
<g id="Layer_19"></g>
|
||||
<g id="Layer_20"></g>
|
||||
<g id="Layer_21"></g>
|
||||
<g id="Layer_24"></g>
|
||||
<g id="Layer_25"></g>
|
||||
<g id="Layer_26"></g>
|
||||
<g id="Layer_27"></g>
|
||||
<g id="Layer_28"></g>
|
||||
<g id="Layer_29"></g>
|
||||
<g id="Layer_47"></g>
|
||||
<g id="Layer_30"></g>
|
||||
<g id="Layer_31"></g>
|
||||
<g id="Layer_32"></g>
|
||||
<g id="Layer_33"></g>
|
||||
<g id="Layer_34"></g>
|
||||
<g id="Layer_35"></g>
|
||||
<g id="Layer_36"></g>
|
||||
<g id="Layer_37"></g>
|
||||
<g id="Layer_38" transform="translate(2.000000, 0.000000)" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M9.7,13.9 L-0.3,7 L9.7,0.1 L10.3,0.9 L1.5,7 L10.3,13.1 L9.7,13.9 Z" id="Shape"></path>
|
||||
</g>
|
||||
<g id="Layer_39"></g>
|
||||
<g id="Layer_40"></g>
|
||||
<g id="Layer_41"></g>
|
||||
<g id="Layer_42"></g>
|
||||
<g id="Layer_43"></g>
|
||||
<g id="Layer_44"></g>
|
||||
<g id="Layer_45"></g>
|
||||
<g id="Layer_46"></g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
55
data/images/nav-forward.svg
Normal file
55
data/images/nav-forward.svg
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<title>nav-forward</title>
|
||||
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="nav-forward" sketch:type="MSLayerGroup" transform="translate(6.000000, 6.000000)">
|
||||
<g id="Layer_2"></g>
|
||||
<g id="Layer_3"></g>
|
||||
<g id="Layer_4"></g>
|
||||
<g id="Layer_5"></g>
|
||||
<g id="Layer_6"></g>
|
||||
<g id="Layer_8"></g>
|
||||
<g id="Layer_9"></g>
|
||||
<g id="Layer_10"></g>
|
||||
<g id="Layer_11"></g>
|
||||
<g id="Layer_12"></g>
|
||||
<g id="Layer_13"></g>
|
||||
<g id="Layer_14"></g>
|
||||
<g id="Layer_15"></g>
|
||||
<g id="Layer_16"></g>
|
||||
<g id="Layer_17"></g>
|
||||
<g id="Layer_18"></g>
|
||||
<g id="Layer_19"></g>
|
||||
<g id="Layer_20"></g>
|
||||
<g id="Layer_21"></g>
|
||||
<g id="Layer_24"></g>
|
||||
<g id="Layer_25"></g>
|
||||
<g id="Layer_26"></g>
|
||||
<g id="Layer_27"></g>
|
||||
<g id="Layer_28"></g>
|
||||
<g id="Layer_29"></g>
|
||||
<g id="Layer_47"></g>
|
||||
<g id="Layer_30"></g>
|
||||
<g id="Layer_31"></g>
|
||||
<g id="Layer_32"></g>
|
||||
<g id="Layer_33"></g>
|
||||
<g id="Layer_34"></g>
|
||||
<g id="Layer_35"></g>
|
||||
<g id="Layer_36"></g>
|
||||
<g id="Layer_37"></g>
|
||||
<g id="Layer_38"></g>
|
||||
<g id="Layer_39"></g>
|
||||
<g id="Layer_40"></g>
|
||||
<g id="Layer_41" transform="translate(2.000000, 0.000000)" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M0.5,13.7 L-0.1,12.9 L8.3,7 L-0.1,1.1 L0.5,0.3 L10.1,7 L0.5,13.7 Z" id="Shape"></path>
|
||||
</g>
|
||||
<g id="Layer_42"></g>
|
||||
<g id="Layer_43"></g>
|
||||
<g id="Layer_44"></g>
|
||||
<g id="Layer_45"></g>
|
||||
<g id="Layer_46"></g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
@@ -102,7 +102,7 @@ Tomahawk.InfoSystem.InfoPlugin = {
|
||||
notInCache: function (infoType, criteria) {
|
||||
var requestMethod = 'request' + this.infoTypeString(infoType);
|
||||
|
||||
return Promise.resolve(this[requestMethod](criteria));
|
||||
return RSVP.Promise.resolve(this[requestMethod](criteria));
|
||||
},
|
||||
pushInfo: function (pushData) {
|
||||
var pushMethod = 'push' + this.infoTypeString(pushData.type);
|
||||
@@ -114,6 +114,6 @@ Tomahawk.InfoSystem.InfoPlugin = {
|
||||
getInfo: function (type, infoHash) {
|
||||
var getInfoMethod = 'get' + this.infoTypeString(type);
|
||||
|
||||
return Promise.resolve(this[getInfoMethod](infoHash));
|
||||
return RSVP.Promise.resolve(this[getInfoMethod](infoHash));
|
||||
}
|
||||
};
|
||||
|
@@ -49,7 +49,7 @@ RSVP.on('error', function (reason) {
|
||||
resolverName = Tomahawk.resolver.instance.settings.name + " - ";
|
||||
}
|
||||
if (reason) {
|
||||
console.error(resolverName + 'Uncaught error:' + JSON.stringify(reason));
|
||||
console.error(resolverName + 'Uncaught error:', reason);
|
||||
} else {
|
||||
console.error(resolverName + 'Uncaught error: error thrown from RSVP but it was empty');
|
||||
}
|
||||
@@ -173,7 +173,8 @@ var TomahawkUrlType = {
|
||||
Playlist: 1,
|
||||
Track: 2,
|
||||
Album: 4,
|
||||
Artist: 8
|
||||
Artist: 8,
|
||||
Xspf: 16
|
||||
};
|
||||
|
||||
//Deprecated for 0.9 resolvers. Use Tomahawk.ConfigTestResultType instead.
|
||||
@@ -236,7 +237,7 @@ var TomahawkResolver = {
|
||||
collection: function () {
|
||||
return {};
|
||||
},
|
||||
_testConfig: function (config) {
|
||||
_adapter_testConfig: function (config) {
|
||||
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
|
||||
return {result: Tomahawk.ConfigTestResultType.Success};
|
||||
});
|
||||
@@ -267,81 +268,28 @@ Tomahawk.Resolver = {
|
||||
},
|
||||
newConfigSaved: function () {
|
||||
},
|
||||
testConfig: function () {
|
||||
},
|
||||
getStreamUrl: function (params) {
|
||||
return params;
|
||||
},
|
||||
|
||||
_convertUrls: function (results) {
|
||||
var that = this;
|
||||
return results.map(function (r) {
|
||||
if (r && r.url) {
|
||||
r.url = that._urlProtocol + '://' + r.url;
|
||||
}
|
||||
return r;
|
||||
_adapter_resolve: function (params) {
|
||||
return RSVP.Promise.resolve(this.resolve(params)).then(function (results) {
|
||||
return {
|
||||
'tracks': results
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_resolve: function (qid, artist, album, title) {
|
||||
var that = this;
|
||||
var collectionPromises = [];
|
||||
Tomahawk.collections.forEach(function (col) {
|
||||
if (col.resolve) {
|
||||
collectionPromises.push(col.resolve({artist: artist, album: album, track: title}));
|
||||
}
|
||||
});
|
||||
RSVP.Promise.all(collectionPromises).then(function (collectionResults) {
|
||||
var merged = [];
|
||||
return merged.concat.apply(merged, collectionResults);
|
||||
}).then(function (collectionResults) {
|
||||
RSVP.Promise.resolve(that.resolve({
|
||||
artist: artist,
|
||||
album: album,
|
||||
track: title
|
||||
})).then(function (results) {
|
||||
Tomahawk.addTrackResults({
|
||||
'qid': qid,
|
||||
'results': that._convertUrls(results.concat(collectionResults))
|
||||
});
|
||||
});
|
||||
_adapter_search: function (params) {
|
||||
return RSVP.Promise.resolve(this.search(params)).then(function (results) {
|
||||
return {
|
||||
'tracks': results
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_init: function () {
|
||||
this._urlProtocol = this.settings.name.replace(/[^a-zA-Z]/g, '').toLowerCase();
|
||||
Tomahawk.addCustomUrlHandler(this._urlProtocol, '_adapter_getStreamUrl', true);
|
||||
Tomahawk.log('Registered custom url handler for protocol "' + this._urlProtocol + '"');
|
||||
this.init();
|
||||
},
|
||||
|
||||
_adapter_getStreamUrl: function (params) {
|
||||
params.url = params.url.slice(this._urlProtocol.length + 3);
|
||||
RSVP.Promise.resolve(this.getStreamUrl(params)).then(function (result) {
|
||||
Tomahawk.reportStreamUrl(params.qid, result.url, result.headers);
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_search: function (qid, query) {
|
||||
var that = this;
|
||||
var collectionPromises = [];
|
||||
Tomahawk.collections.forEach(function (col) {
|
||||
if (col.search) {
|
||||
collectionPromises.push(col.search({query: query}));
|
||||
}
|
||||
});
|
||||
RSVP.Promise.all(collectionPromises).then(function (collectionResults) {
|
||||
var merged = [];
|
||||
return merged.concat.apply(merged, collectionResults);
|
||||
}).then(function (collectionResults) {
|
||||
RSVP.Promise.resolve(that.search({query: query})).then(function (results) {
|
||||
Tomahawk.addTrackResults({
|
||||
'qid': qid,
|
||||
'results': that._convertUrls(results.concat(collectionResults))
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_testConfig: function (config) {
|
||||
_adapter_testConfig: function (config) {
|
||||
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
|
||||
return {result: Tomahawk.ConfigTestResultType.Success};
|
||||
});
|
||||
@@ -364,34 +312,6 @@ Tomahawk.valueForSubNode = function (node, tag) {
|
||||
return element.textContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do a synchronous HTTP(S) request. For further options see
|
||||
* Tomahawk.asyncRequest
|
||||
*/
|
||||
Tomahawk.syncRequest = function (url, extraHeaders, options) {
|
||||
// unpack options
|
||||
var opt = options || {};
|
||||
var method = opt.method || 'GET';
|
||||
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(method, url, false, opt.username, opt.password);
|
||||
if (extraHeaders) {
|
||||
for (var headerName in extraHeaders) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]);
|
||||
}
|
||||
}
|
||||
xmlHttpRequest.send(null);
|
||||
if (httpSuccessStatuses.indexOf(xmlHttpRequest.status) != -1) {
|
||||
return xmlHttpRequest.responseText;
|
||||
} else {
|
||||
Tomahawk.log("Failed to do GET request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
if (opt.hasOwnProperty('errorHandler')) {
|
||||
opt.errorHandler.call(window, xmlHttpRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal counter used to identify retrievedMetadata call back from native
|
||||
* code.
|
||||
@@ -487,6 +407,23 @@ Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
|
||||
delete Tomahawk.asyncRequestCallbacks[reqId];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This method is externalized from Tomahawk.asyncRequest, so that other clients
|
||||
* (like tomahawk-android) can inject their own logic that determines whether or not to do a request
|
||||
* natively.
|
||||
*
|
||||
* @returns boolean indicating whether or not to do a request with the given parameters natively
|
||||
*/
|
||||
var shouldDoNativeRequest = function (options) {
|
||||
var extraHeaders = options.headers;
|
||||
return (extraHeaders && (extraHeaders.hasOwnProperty("Referer")
|
||||
|| extraHeaders.hasOwnProperty("referer")
|
||||
|| extraHeaders.hasOwnProperty("User-Agent")));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Possible options:
|
||||
* - method: The HTTP request method (default: GET)
|
||||
@@ -496,59 +433,45 @@ Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
|
||||
* - data: body data included in POST requests
|
||||
* - needCookieHeader: boolean indicating whether or not the request needs to be able to get the
|
||||
* "Set-Cookie" response header
|
||||
* - headers: headers set on the request
|
||||
*/
|
||||
Tomahawk.asyncRequest = function (url, callback, extraHeaders, options) {
|
||||
// unpack options
|
||||
var opt = options || {};
|
||||
var method = opt.method || 'GET';
|
||||
var doRequest = function(options) {
|
||||
if (shouldDoNativeRequest(options)) {
|
||||
return Tomahawk.NativeScriptJobManager.invoke('httpRequest', options).then(function(xhr) {
|
||||
xhr.responseHeaders = xhr.responseHeaders || {};
|
||||
xhr.getAllResponseHeaders = function() {
|
||||
return this.responseHeaders;
|
||||
};
|
||||
xhr.getResponseHeader = function (header) {
|
||||
return this.responseHeaders[header];
|
||||
};
|
||||
|
||||
if (shouldDoNativeRequest(url, callback, extraHeaders, options)) {
|
||||
// Assign a request Id to the callback so we can use it when we are
|
||||
// returning from the native call.
|
||||
var reqId = Tomahawk.asyncRequestIdCounter;
|
||||
Tomahawk.asyncRequestIdCounter++;
|
||||
Tomahawk.asyncRequestCallbacks[reqId] = {
|
||||
callback: callback,
|
||||
errorHandler: opt.errorHandler
|
||||
};
|
||||
Tomahawk.nativeAsyncRequest(reqId, url, extraHeaders, options);
|
||||
return xhr;
|
||||
});
|
||||
} else {
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(method, url, true, opt.username, opt.password);
|
||||
if (extraHeaders) {
|
||||
for (var headerName in extraHeaders) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]);
|
||||
}
|
||||
}
|
||||
xmlHttpRequest.onreadystatechange = function () {
|
||||
if (xmlHttpRequest.readyState == 4
|
||||
&& httpSuccessStatuses.indexOf(xmlHttpRequest.status) != -1) {
|
||||
callback.call(window, xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do " + method + " request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
if (opt.hasOwnProperty('errorHandler')) {
|
||||
opt.errorHandler.call(window, xmlHttpRequest);
|
||||
return new RSVP.Promise(function(resolve, reject) {
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(options.method, options.url, true, options.username, options.password);
|
||||
if (options.headers) {
|
||||
for (var headerName in options.headers) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, options.headers[headerName]);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlHttpRequest.send(opt.data || null);
|
||||
xmlHttpRequest.onreadystatechange = function () {
|
||||
if (xmlHttpRequest.readyState == 4
|
||||
&& httpSuccessStatuses.indexOf(xmlHttpRequest.status) != -1) {
|
||||
resolve(xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do " + options.method + " request: to: " + options.url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
reject(xmlHttpRequest);
|
||||
}
|
||||
};
|
||||
xmlHttpRequest.send(options.data || null);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is externalized from Tomahawk.asyncRequest, so that other clients
|
||||
* (like tomahawk-android) can inject their own logic that determines whether or not to do a request
|
||||
* natively.
|
||||
*
|
||||
* @returns boolean indicating whether or not to do a request with the given parameters natively
|
||||
*/
|
||||
var shouldDoNativeRequest = function (url, callback, extraHeaders, options) {
|
||||
return (extraHeaders && (extraHeaders.hasOwnProperty("Referer")
|
||||
|| extraHeaders.hasOwnProperty("referer")
|
||||
|| extraHeaders.hasOwnProperty("User-Agent")));
|
||||
};
|
||||
|
||||
Tomahawk.ajax = function (url, settings) {
|
||||
if (typeof url === "object") {
|
||||
settings = url;
|
||||
@@ -606,10 +529,7 @@ Tomahawk.ajax = function (url, settings) {
|
||||
}
|
||||
}
|
||||
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
settings.errorHandler = reject;
|
||||
Tomahawk.asyncRequest(settings.url, resolve, settings.headers, settings);
|
||||
}).then(function (xhr) {
|
||||
return doRequest(settings).then(function (xhr) {
|
||||
if (settings.rawResponse) {
|
||||
return xhr;
|
||||
}
|
||||
@@ -815,7 +735,9 @@ Tomahawk.base64Encode = function (b) {
|
||||
return window.btoa(b);
|
||||
};
|
||||
|
||||
|
||||
Tomahawk.PluginManager = {
|
||||
wrapperPrefix: '_adapter_',
|
||||
objects: {},
|
||||
objectCounter: 0,
|
||||
identifyObject: function (object) {
|
||||
@@ -827,10 +749,6 @@ Tomahawk.PluginManager = {
|
||||
},
|
||||
registerPlugin: function (type, object) {
|
||||
this.objects[this.identifyObject(object)] = object;
|
||||
if (type === 'collection') {
|
||||
Tomahawk.collections.push(object);
|
||||
}
|
||||
|
||||
Tomahawk.log("registerPlugin: " + type + " id: " + object.id);
|
||||
Tomahawk.registerScriptPlugin(type, object.id);
|
||||
},
|
||||
@@ -844,14 +762,11 @@ Tomahawk.PluginManager = {
|
||||
|
||||
resolve: [],
|
||||
invokeSync: function (requestId, objectId, methodName, params) {
|
||||
if (!Tomahawk.resolver.instance.apiVersion || Tomahawk.resolver.instance.apiVersion < 0.9) {
|
||||
if (methodName === 'artistAlbums') {
|
||||
methodName = 'albums';
|
||||
} else if (methodName === 'albumTracks') {
|
||||
methodName = 'tracks';
|
||||
}
|
||||
if (this.objects[objectId][this.wrapperPrefix + methodName]) {
|
||||
methodName = this.wrapperPrefix + methodName;
|
||||
}
|
||||
|
||||
|
||||
var pluginManager = this;
|
||||
if (!this.objects[objectId]) {
|
||||
Tomahawk.log("Object not found! objectId: " + objectId + " methodName: " + methodName);
|
||||
@@ -861,52 +776,13 @@ Tomahawk.PluginManager = {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.objects[objectId][methodName] === 'function') {
|
||||
if (!Tomahawk.resolver.instance.apiVersion
|
||||
|| Tomahawk.resolver.instance.apiVersion < 0.9) {
|
||||
if (methodName == 'artists') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.artists(requestId);
|
||||
});
|
||||
} else if (methodName == 'albums') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.albums(requestId, params.artist);
|
||||
});
|
||||
} else if (methodName == 'tracks') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.tracks(requestId, params.artist, params.album);
|
||||
});
|
||||
} else if (methodName == 'lookupUrl') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[params.url] = resolve;
|
||||
Tomahawk.resolver.instance.lookupUrl(params.url);
|
||||
});
|
||||
} else if (methodName == 'getStreamUrl') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.getStreamUrl(requestId, params.url);
|
||||
});
|
||||
} else if (methodName == 'resolve') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.resolve(requestId, params.artist,
|
||||
params.album, params.track);
|
||||
});
|
||||
} else if (methodName == 'search') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.search(requestId, params.query);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this.objects[objectId][methodName](params);
|
||||
if (typeof this.objects[objectId][methodName] !== 'function' && this.objects[objectId][methodName]) {
|
||||
return this.objects[objectId][methodName];
|
||||
} else if (typeof this.objects[objectId][methodName] !== 'function') {
|
||||
throw new Error('\'' + methodName + '\' on ScriptObject ' + objectId + ' is not a function', typeof this.objects[objectId][methodName]);
|
||||
}
|
||||
|
||||
return this.objects[objectId][methodName];
|
||||
return this.objects[objectId][methodName](params);
|
||||
},
|
||||
|
||||
invoke: function (requestId, objectId, methodName, params) {
|
||||
@@ -925,21 +801,38 @@ Tomahawk.PluginManager = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var encodeParamsToNativeFunctions = function(param) {
|
||||
return param;
|
||||
};
|
||||
|
||||
Tomahawk.NativeScriptJobManager = {
|
||||
idCounter: 0,
|
||||
deferreds: {},
|
||||
invoke: function (methodName, params) {
|
||||
params = params || {};
|
||||
|
||||
var requestId = this.idCounter++;
|
||||
Tomahawk.invokeNativeScriptJob(requestId, methodName, JSON.stringify(params));
|
||||
this.deferreds[requestId] = RSVP.defer();
|
||||
return this.deferreds[requestId].promise;
|
||||
var deferred = RSVP.defer();
|
||||
this.deferreds[requestId] = deferred;
|
||||
Tomahawk.invokeNativeScriptJob(requestId, methodName, encodeParamsToNativeFunctions(params));;
|
||||
return deferred.promise;
|
||||
},
|
||||
reportNativeScriptJobResult: function (requestId, result) {
|
||||
reportNativeScriptJobResult: function(requestId, result) {
|
||||
var deferred = this.deferreds[requestId];
|
||||
if (!deferred) {
|
||||
Tomahawk.log("Deferred object with the given requestId is not present!");
|
||||
}
|
||||
deferred.resolve(result);
|
||||
delete this.deferreds[requestId];
|
||||
},
|
||||
reportNativeScriptJobError: function(requestId, error) {
|
||||
var deferred = this.deferreds[requestId];
|
||||
if (!deferred) {
|
||||
console.log("Deferred object with the given requestId is not present!");
|
||||
}
|
||||
deferred.reject(error);
|
||||
delete this.deferreds[requestId];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1213,8 +1106,6 @@ Tomahawk.Country = {
|
||||
LatinAmericaAndTheCaribbean: 246
|
||||
};
|
||||
|
||||
Tomahawk.collections = [];
|
||||
|
||||
Tomahawk.Collection = {
|
||||
BrowseCapability: {
|
||||
Artists: 1,
|
||||
@@ -1607,6 +1498,10 @@ Tomahawk.Collection = {
|
||||
});
|
||||
},
|
||||
|
||||
revision: function (params) {
|
||||
return RSVP.resolve();
|
||||
},
|
||||
|
||||
_fuzzyIndexIdsToTracks: function (resultIds, id) {
|
||||
if (typeof id === 'undefined') {
|
||||
id = this.settings.id;
|
||||
@@ -1658,6 +1553,14 @@ Tomahawk.Collection = {
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_resolve: function (params) {
|
||||
return RSVP.Promise.resolve(this.resolve(params)).then(function (results) {
|
||||
return {
|
||||
'tracks': results
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
resolve: function (params) {
|
||||
var resultIds = Tomahawk.resolveFromFuzzyIndex(params.artist, params.album, params.track);
|
||||
return this._fuzzyIndexIdsToTracks(resultIds);
|
||||
@@ -1665,7 +1568,12 @@ Tomahawk.Collection = {
|
||||
|
||||
search: function (params) {
|
||||
var resultIds = Tomahawk.searchFuzzyIndex(params.query);
|
||||
return this._fuzzyIndexIdsToTracks(resultIds);
|
||||
|
||||
return this._fuzzyIndexIdsToTracks(resultIds).then(function(tracks) {
|
||||
return {
|
||||
tracks: tracks
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
tracks: function (params, where) {
|
||||
@@ -1709,7 +1617,7 @@ Tomahawk.Collection = {
|
||||
);
|
||||
return t.execDeferredStatements();
|
||||
}).then(function (results) {
|
||||
return {results: Tomahawk.resolver.instance._convertUrls(results[0])};
|
||||
return {tracks: results[0]};
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1883,71 +1791,13 @@ Tomahawk.Collection = {
|
||||
Tomahawk.Collection.BrowseCapability.Albums,
|
||||
Tomahawk.Collection.BrowseCapability.Tracks];
|
||||
return this.settings;
|
||||
},
|
||||
|
||||
getStreamUrl: function(params) {
|
||||
if(this.resolver) {
|
||||
return this.resolver.getStreamUrl(params);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
||||
// Legacy compability for 0.8 and before
|
||||
Tomahawk.reportCapabilities = function (capabilities) {
|
||||
if (capabilities & TomahawkResolverCapability.Browsable) {
|
||||
Tomahawk.PluginManager.registerPlugin("collection", Tomahawk.resolver.instance);
|
||||
}
|
||||
|
||||
Tomahawk.nativeReportCapabilities(capabilities);
|
||||
};
|
||||
|
||||
Tomahawk.addArtistResults = Tomahawk.addAlbumResults = Tomahawk.addAlbumTrackResults
|
||||
= function (result) {
|
||||
Tomahawk.PluginManager.resolve[result.qid](result);
|
||||
delete Tomahawk.PluginManager.resolve[result.qid];
|
||||
};
|
||||
|
||||
Tomahawk.addTrackResults = function (result) {
|
||||
Tomahawk.PluginManager.resolve[result.qid](result.results);
|
||||
delete Tomahawk.PluginManager.resolve[result.qid];
|
||||
};
|
||||
|
||||
Tomahawk.reportStreamUrl = function (qid, streamUrl, headers) {
|
||||
Tomahawk.PluginManager.resolve[qid]({
|
||||
url: streamUrl,
|
||||
headers: headers
|
||||
});
|
||||
delete Tomahawk.PluginManager.resolve[qid];
|
||||
};
|
||||
|
||||
Tomahawk.addUrlResult = function (url, result) {
|
||||
/* Merge the whole mess into one consistent result which is independent of type
|
||||
var cleanResult = {
|
||||
type: result.type,
|
||||
guid: result.guid,
|
||||
info: result.info,
|
||||
creator: result.creator,
|
||||
linkUrl: result.url
|
||||
};
|
||||
if (cleanResult.type == "track") {
|
||||
cleanResult.track = result.title;
|
||||
cleanResult.artist = result.artist;
|
||||
} else if (cleanResult.type == "artist") {
|
||||
cleanResult.artist = result.name;
|
||||
} else if (cleanResult.type == "album") {
|
||||
cleanResult.album = result.name;
|
||||
cleanResult.artist = result.artist;
|
||||
} else if (cleanResult.type == "playlist") {
|
||||
cleanResult.title = result.title;
|
||||
} else if (cleanResult.type == "xspf-url") {
|
||||
cleanResult.url = result.url;
|
||||
}
|
||||
if (result.tracks) {
|
||||
cleanResult.tracks = [];
|
||||
var i;
|
||||
for (i=0;i<result.tracks.length;i++) {
|
||||
var cleanTrack = {
|
||||
track: result.tracks[i].title,
|
||||
artist: result.tracks[i].artist
|
||||
};
|
||||
cleanResult.push(cleanTrack)
|
||||
}
|
||||
Tomahawk.PluginManager.resolve[url](cleanResult);
|
||||
*/
|
||||
Tomahawk.PluginManager.resolve[url](result);
|
||||
delete Tomahawk.PluginManager.resolve[url];
|
||||
};
|
||||
|
@@ -167,5 +167,7 @@
|
||||
<file>data/images/repeat-one.svg</file>
|
||||
<file>data/images/downloads.svg</file>
|
||||
<file>data/images/downloadbutton.svg</file>
|
||||
<file>data/images/nav-back.svg</file>
|
||||
<file>data/images/nav-forward.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -174,7 +174,7 @@ int main( int argc, char* argv[] )
|
||||
reporter.setLogo( QPixmap( CRASHREPORTER_ICON ) );
|
||||
#endif
|
||||
reporter.setWindowTitle( CRASHREPORTER_PRODUCT_NAME );
|
||||
reporter.setText("<html><head/><body><p><span style=\" font-weight:600;\">Sorry!</span> " CRASHREPORTER_PRODUCT_NAME " crashed. Please tell us about it! " CRASHREPORTER_PRODUCT_NAME " has created an error report for you that can help improve the stability in the future. You can now send this report directly to the " CRASHREPORTER_PRODUCT_NAME " developers.</p></body></html>");
|
||||
reporter.setText("<html><head/><body><p><span style=\"font-weight:600;\">Sorry!</span> " CRASHREPORTER_PRODUCT_NAME " crashed. Please tell us about it! " CRASHREPORTER_PRODUCT_NAME " has created an error report for you that can help improve the stability in the future. You can now send this report directly to the " CRASHREPORTER_PRODUCT_NAME " developers.</p><p>Can you tell us what you were doing when this happened?</p></body></html>");
|
||||
|
||||
reporter.setReportData( "BuildID", CRASHREPORTER_BUILD_ID );
|
||||
reporter.setReportData( "ProductName", CRASHREPORTER_PRODUCT_NAME );
|
||||
|
@@ -3,17 +3,15 @@ include_directories(
|
||||
${Boost_INCLUDE_DIR}
|
||||
)
|
||||
if(WIN32 OR APPLE)
|
||||
if(BUILD_GUI AND LIBSNORE_FOUND)
|
||||
if(BUILD_GUI AND LibsnoreQt5_FOUND)
|
||||
SET(snore_srcs
|
||||
snorenotify/SnoreNotifyPlugin.cpp
|
||||
)
|
||||
SET(SNORE_LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBSNORE_LIBRARIES} )
|
||||
|
||||
tomahawk_add_plugin(snorenotify
|
||||
TYPE infoplugin EXPORT_MACRO INFOPLUGINDLLEXPORT_PRO
|
||||
SOURCES "${snore_srcs}" LINK_LIBRARIES "${SNORE_LINK_LIBRARIES}"
|
||||
SOURCES "${snore_srcs}" LINK_LIBRARIES Snore::Libsnore
|
||||
)
|
||||
endif(BUILD_GUI AND LIBSNORE_FOUND)
|
||||
endif()
|
||||
endif(WIN32 OR APPLE)
|
||||
|
||||
list(APPEND simple_plugins
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013-2014, Patrick von Reth <vonreth@kde.org>
|
||||
* Copyright 2013-2015, Hannah von Reth <vonreth@kde.org>
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
@@ -27,27 +27,15 @@
|
||||
|
||||
#include "TomahawkVersion.h"
|
||||
|
||||
#include <snore/core/application.h>
|
||||
#include <snore/core/notification/icon.h>
|
||||
#include <libsnore/application.h>
|
||||
#include <libsnore/notification/icon.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
namespace Qt
|
||||
{
|
||||
inline QString escape( const QString &x )
|
||||
{
|
||||
return x.toHtmlEscaped();
|
||||
}
|
||||
}
|
||||
#else
|
||||
// QTextDocument provides Qt::escape()
|
||||
#include <QTextDocument>
|
||||
#endif
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
@@ -61,27 +49,13 @@ SnoreNotifyPlugin::SnoreNotifyPlugin()
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoTrackUnresolved << InfoNowStopped << InfoInboxReceived;
|
||||
|
||||
m_snore = new Snore::SnoreCore();
|
||||
m_snore->loadPlugins( Snore::SnorePlugin::BACKEND );
|
||||
QString backend = qgetenv( "SNORE_BACKEND" ).constData();
|
||||
|
||||
if( backend.isEmpty() )
|
||||
{
|
||||
m_snore->setPrimaryNotificationBackend();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !m_snore->setPrimaryNotificationBackend( backend ) )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Ivalid or unavailible Snore backend: " << backend << " availible backens: " << m_snore->notificationBackends();
|
||||
m_snore->setPrimaryNotificationBackend();
|
||||
}
|
||||
}
|
||||
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << m_snore->primaryNotificationBackend();
|
||||
Snore::SnoreCore &snore = Snore::SnoreCore::instance();
|
||||
snore.loadPlugins( Snore::SnorePlugin::Backend | Snore::SnorePlugin::SecondaryBackend );
|
||||
snore.setDefaultSettingsValue("Silent", true, Snore::LocalSetting );
|
||||
|
||||
m_application = Snore::Application( qApp->applicationName(), m_defaultIcon );
|
||||
m_application.hints().setValue( "windows_app_id", TOMAHAWK_APPLICATION_PACKAGE_NAME );
|
||||
m_application.hints().setValue( "use-markup", true );
|
||||
m_application.hints().setValue( "windows-app-id", TOMAHAWK_APPLICATION_PACKAGE_NAME );
|
||||
m_application.hints().setValue( "desktop-entry", TOMAHAWK_APPLICATION_NAME );
|
||||
|
||||
addAlert( InfoNotifyUser, tr( "Notify User" ) );
|
||||
@@ -90,9 +64,10 @@ SnoreNotifyPlugin::SnoreNotifyPlugin()
|
||||
addAlert( InfoNowStopped, tr( "Playback Stopped" ) );
|
||||
addAlert( InfoInboxReceived, tr( "You received a Song recommendation" ) );
|
||||
|
||||
m_snore->registerApplication( m_application );
|
||||
snore.registerApplication( m_application );
|
||||
snore.setDefaultApplication( m_application );
|
||||
|
||||
connect( m_snore, SIGNAL( actionInvoked( Snore::Notification ) ), this, SLOT( slotActionInvoked( Snore::Notification ) ) );
|
||||
connect( &snore, SIGNAL( actionInvoked( Snore::Notification ) ), this, SLOT( slotActionInvoked( Snore::Notification ) ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +75,7 @@ SnoreNotifyPlugin::~SnoreNotifyPlugin()
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
|
||||
m_snore->deregisterApplication( m_application );
|
||||
m_snore->deleteLater();
|
||||
Snore::SnoreCore::instance().deregisterApplication( m_application );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -111,25 +85,19 @@ SnoreNotifyPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData )
|
||||
if ( !TomahawkSettings::instance()->songChangeNotificationEnabled() )
|
||||
return;
|
||||
|
||||
if( m_snore->primaryNotificationBackend().isNull() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "no notification backend set";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch ( pushData.type )
|
||||
{
|
||||
case Tomahawk::InfoSystem::InfoTrackUnresolved:
|
||||
notifyUser( Tomahawk::InfoSystem::InfoTrackUnresolved, tr( "The current track could not be resolved. %applicationName will pick back up with the next resolvable track from this source." ) );
|
||||
notifyUser( Tomahawk::InfoSystem::InfoTrackUnresolved, tr( "The current track could not be resolved. %applicationName will pick back up with the next resolvable track from this source." ), m_defaultIcon );
|
||||
return;
|
||||
|
||||
case Tomahawk::InfoSystem::InfoNotifyUser:
|
||||
notifyUser( Tomahawk::InfoSystem::InfoNotifyUser,pushData.infoPair.second.toString() );
|
||||
notifyUser( Tomahawk::InfoSystem::InfoNotifyUser,pushData.infoPair.second.toString(), m_defaultIcon );
|
||||
return;
|
||||
|
||||
case Tomahawk::InfoSystem::InfoNowStopped:
|
||||
notifyUser( Tomahawk::InfoSystem::InfoNowStopped, tr( "%applicationName stopped playback." ) );
|
||||
notifyUser( Tomahawk::InfoSystem::InfoNowStopped, tr( "%applicationName stopped playback." ), m_defaultIcon );
|
||||
return;
|
||||
|
||||
case Tomahawk::InfoSystem::InfoNowPlaying:
|
||||
@@ -157,15 +125,10 @@ SnoreNotifyPlugin::slotActionInvoked( Snore::Notification n )
|
||||
void
|
||||
SnoreNotifyPlugin::notifyUser( Tomahawk::InfoSystem::InfoType type, const QString& messageText, Snore::Icon icon )
|
||||
{
|
||||
if(!icon.isValid())
|
||||
{
|
||||
icon = m_defaultIcon;
|
||||
}
|
||||
const Snore::Alert &alert = m_alerts[ type ];
|
||||
Snore::Notification n( m_application , alert, alert.name(), messageText, icon );
|
||||
m_snore->broadcastNotification( n );
|
||||
Snore::SnoreCore::instance().broadcastNotification( n );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "showing notification:" << messageText;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -194,41 +157,28 @@ SnoreNotifyPlugin::nowPlaying( const QVariant& input )
|
||||
|
||||
QString messageText;
|
||||
// If the window manager supports notification styling then use it.
|
||||
if ( m_snore->primaryBackendSupportsRichtext() )
|
||||
{
|
||||
// Remark: If using xml-based markup in notifications, the supplied strings need to be escaped.
|
||||
QString album;
|
||||
if ( !hash[ "album" ].isEmpty() )
|
||||
album = QString( "<br><i>%1</i> %2" ).arg( tr( "on", "'on' is followed by an album name" ) ).arg( Qt::escape( hash[ "album" ] ) );
|
||||
|
||||
messageText = tr( "%1%4 %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing, %4 is the preposition used to link track and artist ('by' in english)" )
|
||||
.arg( Qt::escape( hash[ "title" ] ) )
|
||||
.arg( Qt::escape( hash[ "artist" ] ) )
|
||||
.arg( album )
|
||||
.arg( QString( "<br><i>%1</i>" ).arg( tr( "by", "preposition to link track and artist" ) ) );
|
||||
// Remark: If using xml-based markup in notifications, the supplied strings need to be escaped.
|
||||
QString album;
|
||||
if ( !hash[ "album" ].isEmpty() )
|
||||
album = QString( "<br><i>%1</i> %2" ).arg( tr( "on", "'on' is followed by an album name" ) ).arg( hash[ "album" ].toHtmlEscaped() );
|
||||
|
||||
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
|
||||
messageText = QString( "<i></i>%1" ).arg( messageText );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString album;
|
||||
if ( !hash[ "album" ].isEmpty() )
|
||||
album = QString( " %1" ).arg( tr( "on \"%1\"", "%1 is an album name" ).arg( hash[ "album" ] ) );
|
||||
messageText = tr( "%1%4 %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing, %4 is the preposition used to link track and artist ('by' in english)" )
|
||||
.arg( hash[ "title" ].toHtmlEscaped() )
|
||||
.arg( hash[ "artist" ].toHtmlEscaped() )
|
||||
.arg( album )
|
||||
.arg( QString( "<br><i>%1</i>" ).arg( tr( "by", "preposition to link track and artist" ) ) );
|
||||
|
||||
messageText = tr( "\"%1\" by %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing" )
|
||||
.arg( hash[ "title" ] )
|
||||
.arg( hash[ "artist" ] )
|
||||
.arg( album );
|
||||
}
|
||||
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
|
||||
messageText = QString( "<i></i>%1" ).arg( messageText );
|
||||
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "sending message" << messageText;
|
||||
|
||||
// If there is a cover availble use it, else use Tomahawk logo as default.
|
||||
Snore::Icon image;
|
||||
Snore::Icon image = m_defaultIcon;
|
||||
if ( map.contains( "cover" ) && map[ "cover" ].canConvert< QImage >() )
|
||||
{
|
||||
image = Snore::Icon( map[ "cover" ].value< QImage >() );
|
||||
image = Snore::Icon( QPixmap::fromImage( map[ "cover" ].value< QImage >() ) );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << image;
|
||||
}
|
||||
notifyUser( InfoNowPlaying, messageText, image );
|
||||
@@ -259,26 +209,15 @@ SnoreNotifyPlugin::inboxReceived( const QVariant& input )
|
||||
return;
|
||||
|
||||
QString messageText;
|
||||
// If the window manager supports notification styling then use it.
|
||||
if ( m_snore->primaryBackendSupportsRichtext() )
|
||||
{
|
||||
// Remark: If using xml-based markup in notifications, the supplied strings need to be escaped.
|
||||
messageText = tr( "%1 sent you\n%2%4 %3.", "%1 is a nickname, %2 is a title, %3 is an artist, %4 is the preposition used to link track and artist ('by' in english)" )
|
||||
.arg( Qt::escape( src["friendlyname"] ) )
|
||||
.arg( Qt::escape( hash[ "title" ] ) )
|
||||
.arg( Qt::escape( hash[ "artist" ] ) )
|
||||
.arg( QString( "\n<i>%1</i>" ).arg( tr( "by", "preposition to link track and artist" ) ) );
|
||||
// Remark: If using xml-based markup in notifications, the supplied strings need to be escaped.
|
||||
messageText = tr( "%1 sent you\n%2%4 %3.", "%1 is a nickname, %2 is a title, %3 is an artist, %4 is the preposition used to link track and artist ('by' in english)" )
|
||||
.arg( src["friendlyname"].toHtmlEscaped() )
|
||||
.arg( hash[ "title" ].toHtmlEscaped() )
|
||||
.arg( hash[ "artist" ].toHtmlEscaped() )
|
||||
.arg( QString( "\n<i>%1</i>" ).arg( tr( "by", "preposition to link track and artist" ) ) );
|
||||
|
||||
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
|
||||
messageText = QString( "<i></i>%1" ).arg( messageText );
|
||||
}
|
||||
else
|
||||
{
|
||||
messageText = tr( "%1 sent you \"%2\" by %3.", "%1 is a nickname, %2 is a title, %3 is an artist" )
|
||||
.arg( src["friendlyname"] )
|
||||
.arg( hash[ "title" ] )
|
||||
.arg( hash[ "artist" ] );
|
||||
}
|
||||
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
|
||||
messageText = QString( "<i></i>%1" ).arg( messageText );
|
||||
|
||||
Snore::Icon icon( RESPATH "images/inbox-512x512.png" );
|
||||
notifyUser( Tomahawk::InfoSystem::InfoInboxReceived, messageText, icon );
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013-2014, Patrick von Reth <vonreth@kde.org>
|
||||
* Copyright 2013-2015, Hannah von Reth <vonreth@kde.org>
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "../../InfoPluginDllMacro.h"
|
||||
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include <snore/core/snore.h>
|
||||
#include <libsnore/snore.h>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
@@ -63,9 +63,8 @@ protected slots:
|
||||
void slotActionInvoked(Snore::Notification n);
|
||||
|
||||
private:
|
||||
void notifyUser( InfoType type, const QString &messageText, Snore::Icon icon = Snore::Icon() );
|
||||
void notifyUser( InfoType type, const QString &messageText, Snore::Icon icon );
|
||||
void addAlert( Tomahawk::InfoSystem::InfoType type, const QString &title );
|
||||
Snore::SnoreCore *m_snore;
|
||||
Snore::Application m_application;
|
||||
Snore::Icon m_defaultIcon;
|
||||
QHash< Tomahawk::InfoSystem::InfoType, Snore::Alert > m_alerts;
|
||||
|
@@ -62,6 +62,8 @@ ActionCollection::~ActionCollection()
|
||||
void
|
||||
ActionCollection::initActions()
|
||||
{
|
||||
// ATTENTION: Don't set ApplicationSpecificRole for submenu actions: they won't show up on OS X (Qt 5.5)
|
||||
|
||||
QAction *latchOn = new QAction( tr( "&Listen Along" ), this );
|
||||
latchOn->setIcon( ImageRegistry::instance()->icon( RESPATH "images/headphones.svg" ) );
|
||||
m_actionCollection[ "latchOn" ] = latchOn;
|
||||
@@ -147,7 +149,6 @@ ActionCollection::initActions()
|
||||
#endif
|
||||
m_actionCollection[ "crashNow" ] = new QAction( "Crash now...", this );
|
||||
m_actionCollection[ "whatsnew_0_8" ] = new QAction( tr( "%applicationName 0.8" ) , this );
|
||||
m_actionCollection[ "whatsnew_0_8" ]->setMenuRole( QAction::ApplicationSpecificRole );
|
||||
m_actionCollection[ "reportBug" ] = new QAction( tr( "Report a Bug" ) , this );
|
||||
m_actionCollection[ "getSupport" ] = new QAction( tr( "Get Support" ) , this );
|
||||
m_actionCollection[ "helpTranslate" ] = new QAction( tr( "Help Us Translate" ) , this );
|
||||
|
@@ -126,6 +126,8 @@ set( libGuiSources
|
||||
utils/LinkGenerator.cpp
|
||||
utils/LinkGeneratorPlugin.cpp
|
||||
utils/TomaHkLinkGeneratorPlugin.cpp
|
||||
utils/LinkParser.cpp
|
||||
utils/LinkParserPlugin.cpp
|
||||
|
||||
viewpages/SearchViewPage.cpp
|
||||
viewpages/SourceViewPage.cpp
|
||||
@@ -199,7 +201,6 @@ list(APPEND libSources
|
||||
MetaPlaylistInterface.cpp
|
||||
Query.cpp
|
||||
Result.cpp
|
||||
ResultProvider.cpp
|
||||
Source.cpp
|
||||
Track.cpp
|
||||
TrackData.cpp
|
||||
@@ -351,8 +352,6 @@ list(APPEND libSources
|
||||
resolvers/ScriptCommand_AllArtists.cpp
|
||||
resolvers/ScriptCommand_AllAlbums.cpp
|
||||
resolvers/ScriptCommand_AllTracks.cpp
|
||||
resolvers/ScriptCommand_LookupUrl.cpp
|
||||
resolvers/ScriptCommandQueue.cpp
|
||||
resolvers/ScriptPluginFactory.cpp
|
||||
|
||||
# ScriptPlugins
|
||||
@@ -360,6 +359,8 @@ list(APPEND libSources
|
||||
resolvers/plugins/ScriptCollectionFactory.cpp
|
||||
resolvers/ScriptInfoPlugin.cpp
|
||||
resolvers/plugins/ScriptInfoPluginFactory.cpp
|
||||
resolvers/plugins/ScriptLinkParserPlugin.cpp
|
||||
resolvers/plugins/ScriptLinkParserPluginFactory.cpp
|
||||
|
||||
|
||||
sip/SipPlugin.cpp
|
||||
@@ -367,6 +368,7 @@ list(APPEND libSources
|
||||
sip/PeerInfo.cpp
|
||||
sip/SipStatusMessage.cpp
|
||||
|
||||
utils/UrlType.cpp
|
||||
utils/Cloudstream.cpp
|
||||
utils/Json.cpp
|
||||
utils/TomahawkUtils.cpp
|
||||
@@ -501,7 +503,7 @@ set_target_properties(
|
||||
AUTOMOC TRUE
|
||||
VERSION ${TOMAHAWK_VERSION_SHORT}
|
||||
SOVERSION ${TOMAHAWK_VERSION_SHORT}
|
||||
OUTPUT_NAME ${TOMAHAWK_TARGET_NAME}
|
||||
OUTPUT_NAME ${TOMAHAWK_BASE_TARGET_NAME}
|
||||
)
|
||||
|
||||
|
||||
@@ -524,7 +526,6 @@ ENDIF( UNIX AND NOT APPLE )
|
||||
TARGET_LINK_LIBRARIES( ${TOMAHAWK_LIBRARY}
|
||||
LINK_PRIVATE
|
||||
${LIBVLC_LIBRARY}
|
||||
${LIBVLCCORE_LIBRARY}
|
||||
|
||||
# Thirdparty shipped with tomahawk
|
||||
${LIBPORTFWD_LIBRARIES}
|
||||
|
@@ -217,7 +217,7 @@ DownloadJob::download()
|
||||
arguments[ "url" ] = m_format.url;
|
||||
|
||||
// HACK: *shrug* WIP.
|
||||
Tomahawk::ScriptJob* job = collection->scriptObject()->invoke( "getStreamUrlPromise", arguments );
|
||||
Tomahawk::ScriptJob* job = collection->scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
connect( job, SIGNAL( done(QVariantMap) ), SLOT( onUrlRetrieved(QVariantMap) ) );
|
||||
job->start();
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2011-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2011-2012, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/XspfLoader.h"
|
||||
#include "utils/LinkParser.h"
|
||||
|
||||
#include "Artist.h"
|
||||
#include "Album.h"
|
||||
@@ -172,12 +174,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
if ( url.contains( "grooveshark.com" ) && url.contains( "playlist" ) )
|
||||
return true;
|
||||
|
||||
// Check Scriptresolvers
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) )
|
||||
return true;
|
||||
}
|
||||
return Tomahawk::Utils::LinkParser::instance()->canParseUrl( url, Tomahawk::Utils::UrlTypePlaylist );
|
||||
}
|
||||
|
||||
if ( acceptedType.testFlag( Track ) )
|
||||
@@ -198,12 +195,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
|| url.contains( "playlists" ) ) ) )
|
||||
return true;
|
||||
|
||||
// Check Scriptresolvers
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Track ) )
|
||||
return true;
|
||||
}
|
||||
return Tomahawk::Utils::LinkParser::instance()->canParseUrl( url, Tomahawk::Utils::UrlTypeTrack );
|
||||
}
|
||||
|
||||
if ( acceptedType.testFlag( Album ) )
|
||||
@@ -215,12 +207,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
if ( url.contains( "rdio.com" ) && ( url.contains( "artist" ) && url.contains( "album" ) && !url.contains( "track" ) ) )
|
||||
return true;
|
||||
|
||||
// Check Scriptresolvers
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Album ) )
|
||||
return true;
|
||||
}
|
||||
return Tomahawk::Utils::LinkParser::instance()->canParseUrl( url, Tomahawk::Utils::UrlTypeAlbum );
|
||||
}
|
||||
|
||||
if ( acceptedType.testFlag( Artist ) )
|
||||
@@ -232,12 +219,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
if ( url.contains( "rdio.com" ) && ( url.contains( "artist" ) && !url.contains( "album" ) && !url.contains( "track" ) ) )
|
||||
return true;
|
||||
|
||||
// Check Scriptresolvers
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Artist ) )
|
||||
return true;
|
||||
}
|
||||
return Tomahawk::Utils::LinkParser::instance()->canParseUrl( url, Tomahawk::Utils::UrlTypeArtist );
|
||||
}
|
||||
|
||||
// We whitelist certain url-shorteners since they do some link checking. Often playable (e.g. spotify) links hide behind them,
|
||||
@@ -303,15 +285,7 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data )
|
||||
if ( ShortenedLinkParser::handlesUrl( url ) )
|
||||
return true;
|
||||
|
||||
// Check Scriptresolvers
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Accepting current drop as a playlist" << resolver->name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Tomahawk::Utils::LinkParser::instance()->canParseUrl( url, Tomahawk::Utils::UrlTypePlaylist );
|
||||
|
||||
}
|
||||
|
||||
@@ -761,16 +735,12 @@ DropJob::handleTrackUrls( const QString& urls )
|
||||
|
||||
foreach ( QString track, tracks )
|
||||
{
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
QList< QSharedPointer< Utils::LinkParserPlugin > > parserPlugins = Utils::LinkParser::instance()->parserPluginsForUrl( track, Utils::UrlTypeAny );
|
||||
if( !parserPlugins.isEmpty() )
|
||||
{
|
||||
if ( resolver->canParseUrl( track, ExternalResolver::Any ) )
|
||||
{
|
||||
ScriptCommand_LookupUrl* cmd = new ScriptCommand_LookupUrl( resolver, track );
|
||||
connect( cmd, SIGNAL( information( QString, QSharedPointer<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ) );
|
||||
cmd->enqueue();
|
||||
m_queryCount++;
|
||||
break;
|
||||
}
|
||||
Tomahawk::Utils::LinkParser::instance()->lookupUrl( track, parserPlugins );
|
||||
connect( Tomahawk::Utils::LinkParser::instance(), SIGNAL( informationFound( QString, QSharedPointer<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ) );
|
||||
m_queryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2011-2014, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright (C) 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright (C) 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright (C) 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,13 +36,13 @@
|
||||
#include "playlist/TrackView.h"
|
||||
#include "playlist/PlayableModel.h"
|
||||
#include "resolvers/ExternalResolver.h"
|
||||
#include "resolvers/ScriptCommand_LookupUrl.h"
|
||||
#include "utils/JspfLoader.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/SpotifyParser.h"
|
||||
#include "utils/XspfLoader.h"
|
||||
#include "utils/XspfGenerator.h"
|
||||
#include "viewpages/SearchViewPage.h"
|
||||
#include "utils/LinkParser.h"
|
||||
|
||||
#include "Pipeline.h"
|
||||
#include "TomahawkSettings.h"
|
||||
@@ -162,27 +163,12 @@ GlobalActionManager::openUrl( const QString& url )
|
||||
else if ( url.contains( "open.spotify.com" ) || url.startsWith( "spotify:" ) )
|
||||
return openSpotifyLink( url );
|
||||
|
||||
// Can we parse the Url using a ScriptResolver?
|
||||
bool canParse = false;
|
||||
QList< QPointer< ExternalResolver > > possibleResolvers;
|
||||
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
|
||||
// Can we parse the Url using LinkParser?
|
||||
QList< QSharedPointer< Utils::LinkParserPlugin > > parserPlugins = Utils::LinkParser::instance()->parserPluginsForUrl( url, Utils::UrlTypeAny );
|
||||
if( !parserPlugins.isEmpty() )
|
||||
{
|
||||
if ( resolver->canParseUrl( url, ExternalResolver::Any ) )
|
||||
{
|
||||
canParse = true;
|
||||
possibleResolvers << resolver;
|
||||
}
|
||||
}
|
||||
if ( canParse )
|
||||
{
|
||||
m_queuedUrl = url;
|
||||
foreach ( QPointer<ExternalResolver> resolver, possibleResolvers )
|
||||
{
|
||||
ScriptCommand_LookupUrl* cmd = new ScriptCommand_LookupUrl( resolver, url );
|
||||
connect( cmd, SIGNAL( information( QString, QSharedPointer<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ) );
|
||||
cmd->enqueue();
|
||||
}
|
||||
|
||||
Tomahawk::Utils::LinkParser::instance()->lookupUrl( url, parserPlugins );
|
||||
connect( Tomahawk::Utils::LinkParser::instance(), SIGNAL( informationFound( QString, QSharedPointer<QObject> ) ), this, SLOT( informationForUrl( QString, QSharedPointer<QObject> ) ), Qt::UniqueConnection );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -149,6 +149,15 @@ Pipeline::removeResolver( Resolver* r )
|
||||
}
|
||||
|
||||
|
||||
QList< Tomahawk::Resolver* >
|
||||
Pipeline::resolvers() const
|
||||
{
|
||||
Q_D( const Pipeline );
|
||||
|
||||
return d->resolvers;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pipeline::addResolver( Resolver* r )
|
||||
{
|
||||
@@ -323,6 +332,13 @@ Pipeline::resolve( QID qid, bool prioritized, bool temporaryQuery )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pipeline::reportError( QID qid, Tomahawk::Resolver* r )
|
||||
{
|
||||
reportResults( qid, r, QList< result_ptr>() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pipeline::reportResults( QID qid, Tomahawk::Resolver* r, const QList< result_ptr >& results )
|
||||
{
|
||||
@@ -333,7 +349,7 @@ Pipeline::reportResults( QID qid, Tomahawk::Resolver* r, const QList< result_ptr
|
||||
{
|
||||
if ( !results.isEmpty() )
|
||||
{
|
||||
ResultProvider* resolvedBy = results[0]->resolvedBy();
|
||||
Resolver* resolvedBy = results[0]->resolvedBy();
|
||||
if ( resolvedBy )
|
||||
{
|
||||
tDebug() << "Result arrived too late for:" << qid << "by" << resolvedBy->name();
|
||||
|
@@ -54,6 +54,7 @@ public:
|
||||
unsigned int pendingQueryCount() const;
|
||||
unsigned int activeQueryCount() const;
|
||||
|
||||
void reportError( QID qid, Tomahawk::Resolver* r );
|
||||
void reportResults( QID qid, Tomahawk::Resolver* r, const QList< result_ptr >& results );
|
||||
void reportAlbums( QID qid, const QList< album_ptr >& albums );
|
||||
void reportArtists( QID qid, const QList< artist_ptr >& artists );
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
QList< QPointer< ExternalResolver > > scriptResolvers() const;
|
||||
Tomahawk::ExternalResolver* resolverForPath( const QString& scriptPath );
|
||||
|
||||
QList< Resolver* > resolvers() const;
|
||||
void addResolver( Resolver* r );
|
||||
void removeResolver( Resolver* r );
|
||||
|
||||
|
@@ -491,7 +491,7 @@ Result::setFileId( unsigned int id )
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ResultProvider*
|
||||
Tomahawk::Resolver*
|
||||
Result::resolvedBy() const
|
||||
{
|
||||
if ( !m_collection.isNull() )
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#ifndef RESULT_H
|
||||
#define RESULT_H
|
||||
|
||||
#include "ResultProvider.h"
|
||||
#include "DownloadJob.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "Typedefs.h"
|
||||
@@ -86,9 +85,9 @@ public:
|
||||
void setResolvedByResolver( Tomahawk::Resolver* resolver );
|
||||
|
||||
/**
|
||||
* This is very bad. ResultProvider is not a QObject and thus can not be tracked by a qt smart pointer ... :-(
|
||||
* TODO: Make this a smart pointer
|
||||
*/
|
||||
ResultProvider* resolvedBy() const;
|
||||
Resolver* resolvedBy() const;
|
||||
|
||||
RID id() const;
|
||||
bool isOnline() const;
|
||||
|
@@ -76,6 +76,8 @@ public:
|
||||
*/
|
||||
virtual bool addPageItem() const;
|
||||
|
||||
virtual bool isRemovable() const { return false; }
|
||||
|
||||
/**
|
||||
* This page is actually a constant page that will be shown on every
|
||||
* restart of Tomahawk until the user selects it to be removed.
|
||||
|
@@ -524,7 +524,7 @@ void ResolverAccount::testConfig()
|
||||
if ( resolver )
|
||||
{
|
||||
QVariantMap data = resolver->loadDataFromWidgets();
|
||||
ScriptJob* job = resolver->scriptObject()->invoke( "_testConfig", data );
|
||||
ScriptJob* job = resolver->scriptObject()->invoke( "testConfig", data );
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onTestConfig( QVariantMap ) ) );
|
||||
job->start();
|
||||
}
|
||||
|
@@ -65,13 +65,6 @@ LastFmInfoPlugin::init()
|
||||
return;
|
||||
}
|
||||
|
||||
lastfm::ws::ApiKey = "7194b85b6d1f424fe1668173a78c0c4a";
|
||||
lastfm::ws::SharedSecret = "ba80f1df6d27ae63e9cb1d33ccf2052f";
|
||||
lastfm::ws::Username = m_account.data()->username();
|
||||
lastfm::setNetworkAccessManager( Tomahawk::Utils::nam() );
|
||||
|
||||
m_pw = m_account.data()->password();
|
||||
|
||||
//HACK work around a bug in liblastfm---it doesn't create its config dir, so when it
|
||||
// tries to write the track cache, it fails silently. until we have a fixed version, do this
|
||||
// code taken from Amarok (src/services/lastfm/ScrobblerAdapter.cpp)
|
||||
@@ -86,6 +79,17 @@ LastFmInfoPlugin::init()
|
||||
|
||||
m_badUrls << QUrl( "http://cdn.last.fm/flatness/catalogue/noimage" );
|
||||
|
||||
|
||||
lastfm::ws::ApiKey = "7194b85b6d1f424fe1668173a78c0c4a";
|
||||
lastfm::ws::SharedSecret = "ba80f1df6d27ae63e9cb1d33ccf2052f";
|
||||
lastfm::setNetworkAccessManager( Tomahawk::Utils::nam() );
|
||||
|
||||
if ( !m_account.isNull() )
|
||||
{
|
||||
lastfm::ws::Username = m_account->username();
|
||||
m_pw = m_account->password();
|
||||
}
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( settingsChanged() ) );
|
||||
}
|
||||
|
||||
|
@@ -842,15 +842,28 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
||||
const QString qid = msg.value( "qid" ).toString();
|
||||
if ( m_qidToSlotMap.contains( qid ) )
|
||||
{
|
||||
QObject* receiver = m_qidToSlotMap[ qid ].first;
|
||||
QPointer< QObject > receiver = m_qidToSlotMap[ qid ].first;
|
||||
QString slot = m_qidToSlotMap[ qid ].second;
|
||||
m_qidToSlotMap.remove( qid );
|
||||
|
||||
|
||||
QVariant extraData;
|
||||
if ( m_qidToExtraData.contains( qid ) )
|
||||
extraData = m_qidToExtraData.take( qid );
|
||||
|
||||
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ), Q_ARG( QVariant, extraData ) );
|
||||
// FIXME: SpotifyParser is sometimes a dangling pointer, haven't found a real way to reproduce: happens sometimes when dropping a playlist url onto the sidebar
|
||||
//Q_ASSERT( !receiver.isNull() );
|
||||
|
||||
if ( !receiver.isNull() )
|
||||
{
|
||||
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ), Q_ARG( QVariant, extraData ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage(
|
||||
tr( "Spotify account could not finish action. Try again." )
|
||||
) );
|
||||
}
|
||||
}
|
||||
else if ( msgType == "allPlaylists" )
|
||||
{
|
||||
|
@@ -172,7 +172,7 @@ private:
|
||||
QPointer<ScriptResolver> m_spotifyResolver;
|
||||
QPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
|
||||
|
||||
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
|
||||
QMap<QString, QPair< QPointer< QObject >, QString> > m_qidToSlotMap;
|
||||
QMap<QString, QVariant > m_qidToExtraData;
|
||||
|
||||
// List of synced spotify playlists in config UI
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include "playlist/SingleTrackPlaylistInterface.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NetworkReply.h"
|
||||
#include "utils/NetworkAccessManager.h"
|
||||
|
||||
#include "Album.h"
|
||||
#include "Artist.h"
|
||||
@@ -40,6 +42,7 @@
|
||||
#include "SourceList.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "UrlHandler.h"
|
||||
#include "resolvers/ScriptJob.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
@@ -574,16 +577,64 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
|
||||
setCurrentTrack( result );
|
||||
|
||||
if ( !TomahawkUtils::isLocalResult( d->currentTrack->url() ) && !TomahawkUtils::isHttpResult( d->currentTrack->url() )
|
||||
&& !TomahawkUtils::isRtmpResult( d->currentTrack->url() ) )
|
||||
ScriptJob* job = result->resolvedBy()->getStreamUrl( result );
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( gotStreamUrl( QVariantMap ) ) );
|
||||
job->setProperty( "result", QVariant::fromValue( result ) );
|
||||
job->start();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::gotStreamUrl( const QVariantMap& data )
|
||||
{
|
||||
QString streamUrl = data[ "url" ].toString();
|
||||
QVariantMap headers = data[ "headers" ].toMap();
|
||||
Tomahawk::result_ptr result = sender()->property( "result" ).value<result_ptr>();
|
||||
|
||||
if ( streamUrl.isEmpty() || !( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) || TomahawkUtils::isRtmpResult( streamUrl ) ) )
|
||||
{
|
||||
performLoadIODevice( d->currentTrack, d->currentTrack->url() );
|
||||
// Not an http(s) or RTMP URL, get IO device
|
||||
QSharedPointer< QIODevice > sp;
|
||||
performLoadIODevice( result, streamUrl );
|
||||
}
|
||||
else
|
||||
{
|
||||
QSharedPointer< QIODevice > io;
|
||||
performLoadTrack( result, result->url(), io );
|
||||
// TODO: just make this part of the http(s) IoDeviceFactory (?)
|
||||
QUrl url = QUrl::fromEncoded( streamUrl.toUtf8() );
|
||||
QNetworkRequest req( url );
|
||||
|
||||
QMap<QString, QString> parsedHeaders;
|
||||
foreach ( const QString& key, headers.keys() )
|
||||
{
|
||||
Q_ASSERT_X( headers[key].canConvert( QVariant::String ), Q_FUNC_INFO, "Expected a Map of string for additional headers" );
|
||||
if ( headers[key].canConvert( QVariant::String ) )
|
||||
{
|
||||
parsedHeaders.insert( key, headers[key].toString() );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( const QString& key, parsedHeaders.keys() )
|
||||
{
|
||||
req.setRawHeader( key.toLatin1(), parsedHeaders[key].toLatin1() );
|
||||
}
|
||||
|
||||
tDebug() << "Creating a QNetworkReply with url:" << req.url().toString();
|
||||
NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( req ) );
|
||||
NewClosure( reply, SIGNAL( finalUrlReached() ), this, SLOT( gotRedirectedStreamUrl( Tomahawk::result_ptr, NetworkReply* )), result, reply );
|
||||
}
|
||||
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply )
|
||||
{
|
||||
// std::functions cannot accept temporaries as parameters
|
||||
QSharedPointer< QIODevice > sp ( reply->reply(), &QObject::deleteLater );
|
||||
QString url = reply->reply()->url().toString();
|
||||
reply->disconnectFromReply();
|
||||
reply->deleteLater();
|
||||
|
||||
performLoadTrack( result, url, sp );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
class NetworkReply;
|
||||
class AudioEnginePrivate;
|
||||
|
||||
class DLLEXPORT AudioEngine : public QObject
|
||||
@@ -180,6 +181,10 @@ signals:
|
||||
|
||||
private slots:
|
||||
void loadTrack( const Tomahawk::result_ptr& result ); //async!
|
||||
void gotStreamUrl( const QVariantMap& data );
|
||||
void gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply );
|
||||
|
||||
|
||||
void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url ); //only call from loadTrack kthxbi
|
||||
void performLoadTrack( const Tomahawk::result_ptr result, const QString url, QSharedPointer< QIODevice > io ); //only call from loadTrack or performLoadIODevice kthxbi
|
||||
void loadPreviousTrack();
|
||||
|
@@ -35,7 +35,7 @@ using namespace Tomahawk;
|
||||
|
||||
|
||||
Collection::Collection( const source_ptr& source, const QString& name, QObject* parent )
|
||||
: QObject( parent )
|
||||
: Resolver( parent )
|
||||
, m_name( name )
|
||||
, m_lastmodified( 0 )
|
||||
, m_changed( false )
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "collection/ArtistsRequest.h"
|
||||
#include "collection/AlbumsRequest.h"
|
||||
#include "collection/TracksRequest.h"
|
||||
#include "../ResultProvider.h"
|
||||
#include "../resolvers/Resolver.h"
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class DLLEXPORT Collection : public QObject, public ResultProvider
|
||||
class DLLEXPORT Collection : public Resolver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -251,3 +251,32 @@ DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Resolver interface
|
||||
*
|
||||
* We implement searching the database in the DatabaseResolver which avoids a n+1 query here.
|
||||
* We can't simply let ScriptCollection inherit Collection and Resolver because both are QObjects,
|
||||
* although Resolver doesn't need to be a QObject atm, blocking adding signals/slots to Resolver
|
||||
* in future seems to me worse than violating Liskov's law here. ~ domme
|
||||
*/
|
||||
unsigned int
|
||||
DatabaseCollection::timeout() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
DatabaseCollection::weight() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCollection::resolve( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
Q_UNUSED( query );
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
@@ -65,6 +65,11 @@ public:
|
||||
int trackCount() const override;
|
||||
QPixmap icon( const QSize& size ) const override;
|
||||
|
||||
// Resolver interface
|
||||
unsigned int weight() const override;
|
||||
unsigned int timeout() const override;
|
||||
void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
|
||||
public slots:
|
||||
virtual void addTracks( const QList<QVariant>& newitems );
|
||||
virtual void removeTracks( const QDir& dir );
|
||||
|
@@ -262,8 +262,15 @@ TrackDetailView::onResultsChanged()
|
||||
resolverLabel->setFont( f );
|
||||
resolverLabel->setStyleSheet( "QLabel { color: rgba( 0, 0, 0, 50% ) }" );
|
||||
resolverLabel->setText( QString( "%1 - %2" ).arg( result->track()->track() ).arg( result->track()->artist() ) );
|
||||
resolverLabel->setToolTip( QString( "%1 by %2%3" ).arg( result->track()->track() ).arg( result->track()->artist() )
|
||||
.arg( !result->track()->album().isEmpty() ? QString( " " ) + tr( "on %1" ).arg( result->track()->album() ) : QString() ) );
|
||||
resolverLabel->setToolTip(
|
||||
QString( "%1 by %2%3 (%4)" )
|
||||
.arg( result->track()->track() )
|
||||
.arg( result->track()->artist() )
|
||||
.arg( !result->track()->album().isEmpty() ? QString( " " ) + tr( "on %1" ).arg( result->track()->album() ) : QString() )
|
||||
.arg( result->friendlySource() )
|
||||
);
|
||||
|
||||
;
|
||||
resolverLabel->setFixedWidth( width() - 32 - 4 );
|
||||
|
||||
NewClosure( resolverLabel, SIGNAL( clicked() ), const_cast< AudioEngine* >( AudioEngine::instance() ),
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,8 +25,6 @@
|
||||
#include "Source.h"
|
||||
#include "DllMacro.h"
|
||||
#include "Resolver.h"
|
||||
#include "ScriptCommandQueue.h"
|
||||
#include "ScriptCommand_LookupUrl.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
#include <QObject>
|
||||
@@ -45,7 +44,6 @@ class DLLEXPORT ExternalResolver : public Resolver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ScriptCommandQueue;
|
||||
friend class ScriptCommand_LookupUrl;
|
||||
|
||||
public:
|
||||
@@ -61,25 +59,13 @@ public:
|
||||
Browsable = 0x1, // can be represented in one or more collection tree views
|
||||
PlaylistSync = 0x2, // can sync playlists
|
||||
AccountFactory = 0x4, // can configure multiple accounts at the same time
|
||||
UrlLookup = 0x8 // can be queried for information on an Url
|
||||
};
|
||||
Q_DECLARE_FLAGS( Capabilities, Capability )
|
||||
Q_FLAGS( Capabilities )
|
||||
|
||||
enum UrlType
|
||||
{
|
||||
Any = 0x00,
|
||||
Playlist = 0x01,
|
||||
Track = 0x02,
|
||||
Album = 0x04,
|
||||
Artist = 0x08
|
||||
};
|
||||
Q_DECLARE_FLAGS( UrlTypes, UrlType )
|
||||
Q_FLAGS( UrlTypes )
|
||||
|
||||
ExternalResolver( const QString& filePath )
|
||||
: m_commandQueue( new ScriptCommandQueue( this ) )
|
||||
{ m_filePath = filePath; }
|
||||
: m_filePath( filePath )
|
||||
{}
|
||||
|
||||
QString filePath() const { return m_filePath; }
|
||||
virtual void setIcon( const QPixmap& ) {}
|
||||
@@ -91,12 +77,6 @@ public:
|
||||
virtual bool running() const = 0;
|
||||
virtual Capabilities capabilities() const = 0;
|
||||
|
||||
// UrlLookup, sync call
|
||||
virtual bool canParseUrl( const QString& url, UrlType type ) = 0;
|
||||
|
||||
virtual void enqueue( const QSharedPointer< ScriptCommand >& req )
|
||||
{ m_commandQueue->enqueue( req ); }
|
||||
|
||||
public slots:
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
@@ -111,11 +91,6 @@ signals:
|
||||
|
||||
protected:
|
||||
void setFilePath( const QString& path ) { m_filePath = path; }
|
||||
ScriptCommandQueue* m_commandQueue;
|
||||
|
||||
// Should only be called by ScriptCommands
|
||||
// UrlLookup
|
||||
virtual void lookupUrl( const QString& url ) = 0;
|
||||
|
||||
private:
|
||||
QString m_filePath;
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <QWidget>
|
||||
#include <QUiLoader>
|
||||
#include <QBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QDesktopServices>
|
||||
|
||||
Tomahawk::ExternalResolverGui::ExternalResolverGui(const QString& filePath)
|
||||
: Tomahawk::ExternalResolver(filePath)
|
||||
@@ -82,6 +84,30 @@ Tomahawk::ExternalResolverGui::addChildProperties( QObject* widget, QVariantMap&
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Tomahawk::ExternalResolverGui::setupClickHandlerOnUrlButtons( QObject* widget )
|
||||
{
|
||||
if( !widget || !widget->isWidgetType() )
|
||||
return;
|
||||
|
||||
if( qstrcmp( widget->metaObject()->className(), "QPushButton" ) == 0 && !widget->property( "url" ).isNull() )
|
||||
{
|
||||
QPushButton* button = qobject_cast< QPushButton* >( widget );
|
||||
Q_ASSERT( button );
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
connect( button, &QPushButton::clicked, [=]() {
|
||||
QDesktopServices::openUrl( widget->property( "url" ).toUrl() );
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
// and recurse
|
||||
foreach( QObject* child, widget->children() )
|
||||
setupClickHandlerOnUrlButtons( child );
|
||||
}
|
||||
|
||||
|
||||
AccountConfigWidget*
|
||||
Tomahawk::ExternalResolverGui::widgetFromData( QByteArray& data, QWidget* parent )
|
||||
{
|
||||
@@ -94,6 +120,8 @@ Tomahawk::ExternalResolverGui::widgetFromData( QByteArray& data, QWidget* parent
|
||||
QBuffer b( &data );
|
||||
QWidget* w = l.load( &b, configWidget );
|
||||
|
||||
setupClickHandlerOnUrlButtons( w );
|
||||
|
||||
// HACK: proper way would be to create a designer plugin for this widget type
|
||||
configWidget->setLayout( new QBoxLayout( QBoxLayout::TopToBottom ) );
|
||||
configWidget->layout()->addWidget( w );
|
||||
|
@@ -50,7 +50,8 @@ protected:
|
||||
QByteArray fixDataImagePaths( const QByteArray& data, bool compressed, const QVariantMap& images );
|
||||
|
||||
private:
|
||||
void addChildProperties( QObject* parent, QVariantMap& m );
|
||||
void addChildProperties( QObject* widget, QVariantMap& m );
|
||||
void setupClickHandlerOnUrlButtons( QObject* widget );
|
||||
};
|
||||
|
||||
}; //ns
|
||||
|
@@ -170,6 +170,41 @@ JSAccount::syncInvoke( const scriptobject_ptr& scriptObject, const QString& meth
|
||||
return evaluateJavaScriptWithResult( eval );
|
||||
}
|
||||
|
||||
void
|
||||
JSAccount::reportNativeScriptJobResult( int resultId, const QVariantMap& result )
|
||||
{
|
||||
QString eval = QString(
|
||||
"Tomahawk.NativeScriptJobManager.reportNativeScriptJobResult("
|
||||
"%1," // requestId
|
||||
"%2" // results
|
||||
");"
|
||||
).arg( resultId )
|
||||
.arg( serializeQVariantMap( result ) );
|
||||
|
||||
// Remove when new scripting api turned out to work reliably
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval;
|
||||
|
||||
evaluateJavaScript( eval );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSAccount::reportNativeScriptJobError( int resultId, const QVariantMap& error )
|
||||
{
|
||||
QString eval = QString(
|
||||
"Tomahawk.NativeScriptJobManager.reportNativeScriptJobError("
|
||||
"%1," // requestId
|
||||
"%2" // results
|
||||
");"
|
||||
).arg( resultId )
|
||||
.arg( serializeQVariantMap( error ) );
|
||||
|
||||
// Remove when new scripting api turned out to work reliably
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval;
|
||||
|
||||
evaluateJavaScript( eval );
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
JSAccount::evaluateJavaScriptInternal( const QString& scriptSource )
|
||||
|
@@ -71,13 +71,16 @@ public:
|
||||
|
||||
static QString serializeQVariantMap(const QVariantMap& map);
|
||||
|
||||
void reportNativeScriptJobResult( int resultId, const QVariantMap& result ) override;
|
||||
void reportNativeScriptJobError( int resultId, const QVariantMap& error ) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Wrap the pure evaluateJavaScript call in here, while the threadings guards are in public methods
|
||||
*/
|
||||
QVariant evaluateJavaScriptInternal( const QString& scriptSource );
|
||||
|
||||
std::unique_ptr<ScriptEngine> m_engine;
|
||||
ScriptEngine* m_engine;
|
||||
// HACK: the order of initializen is flawed, tbr
|
||||
JSResolver* m_resolver;
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,6 +45,9 @@
|
||||
#include "Track.h"
|
||||
#include "ScriptInfoPlugin.h"
|
||||
#include "JSAccount.h"
|
||||
#include "ScriptJob.h"
|
||||
#include "database/Database.h"
|
||||
#include "database/DatabaseImpl.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -250,12 +254,11 @@ JSResolver::init()
|
||||
d->scriptAccount->loadScript( filePath() );
|
||||
|
||||
// HACK: register resolver object
|
||||
d->scriptAccount->evaluateJavaScript( "Tomahawk.PluginManager.registerPlugin('resolver', Tomahawk.resolver.instance);" )
|
||||
;
|
||||
d->scriptAccount->evaluateJavaScript( "Tomahawk.PluginManager.registerPlugin('resolver', Tomahawk.resolver.instance);" );
|
||||
// init resolver
|
||||
resolverInit();
|
||||
scriptObject()->syncInvoke( "init" );
|
||||
|
||||
QVariantMap m = resolverSettings();
|
||||
QVariantMap m = scriptObject()->syncInvoke( "settings" ).toMap();
|
||||
d->name = m.value( "name" ).toString();
|
||||
d->weight = m.value( "weight", 0 ).toUInt();
|
||||
d->timeout = m.value( "timeout", 25 ).toUInt() * 1000;
|
||||
@@ -305,6 +308,8 @@ JSResolver::start()
|
||||
Q_D( JSResolver );
|
||||
|
||||
d->stopped = false;
|
||||
d->resolverHelper->start();
|
||||
|
||||
if ( d->ready )
|
||||
Tomahawk::Pipeline::instance()->addResolver( this );
|
||||
else
|
||||
@@ -314,65 +319,16 @@ JSResolver::start()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
JSResolver::canParseUrl( const QString& url, UrlType type )
|
||||
{
|
||||
Q_D( const JSResolver );
|
||||
|
||||
// FIXME: How can we do this?
|
||||
/*if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "canParseUrl", Qt::QueuedConnection,
|
||||
Q_ARG( QString, url ) );
|
||||
return;
|
||||
}*/
|
||||
|
||||
if ( d->capabilities.testFlag( UrlLookup ) )
|
||||
{
|
||||
QString eval = QString( "canParseUrl( '%1', %2 )" )
|
||||
.arg( JSAccount::escape( QString( url ) ) )
|
||||
.arg( (int) type );
|
||||
return callOnResolver( eval ).toBool();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We cannot do URL lookup.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolver::lookupUrl( const QString& url )
|
||||
JSResolver::tracksAdded( const QList<query_ptr>&, const ModelMode, const collection_ptr&)
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "lookupUrl", Qt::QueuedConnection,
|
||||
Q_ARG( QString, url ) );
|
||||
// Check if we still are actively waiting
|
||||
if ( m_pendingAlbum.isNull() || m_pendingUrl.isNull() )
|
||||
return;
|
||||
}
|
||||
|
||||
Q_D( const JSResolver );
|
||||
|
||||
if ( !d->capabilities.testFlag( UrlLookup ) )
|
||||
{
|
||||
emit informationFound( url, QSharedPointer<QObject>() );
|
||||
return;
|
||||
}
|
||||
|
||||
QString eval = QString( "lookupUrl( '%1' )" )
|
||||
.arg( JSAccount::escape( QString( url ) ) );
|
||||
|
||||
QVariantMap m = callOnResolver( eval ).toMap();
|
||||
if ( m.isEmpty() )
|
||||
{
|
||||
// if the resolver doesn't return anything, async api is used
|
||||
return;
|
||||
}
|
||||
|
||||
QString errorMessage = tr( "Script Resolver Warning: API call %1 returned data synchronously." ).arg( eval );
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorMessage ) );
|
||||
tDebug() << errorMessage << m;
|
||||
emit informationFound( m_pendingUrl, m_pendingAlbum.objectCast<QObject>() );
|
||||
m_pendingAlbum = album_ptr();
|
||||
m_pendingUrl = QString();
|
||||
}
|
||||
|
||||
|
||||
@@ -388,38 +344,51 @@ JSResolver::error() const
|
||||
void
|
||||
JSResolver::resolve( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "resolve", Qt::QueuedConnection, Q_ARG(Tomahawk::query_ptr, query) );
|
||||
return;
|
||||
}
|
||||
ScriptJob* job = scriptAccount()->resolve( scriptObject(), query, "resolver" );
|
||||
|
||||
QString eval;
|
||||
if ( !query->isFullTextQuery() )
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onResolveRequestDone( QVariantMap ) ) );
|
||||
|
||||
job->start();
|
||||
}
|
||||
|
||||
void
|
||||
JSResolver::onResolveRequestDone( const QVariantMap& data )
|
||||
{
|
||||
Q_ASSERT( QThread::currentThread() == thread() );
|
||||
Q_D( JSResolver );
|
||||
|
||||
ScriptJob* job = qobject_cast< ScriptJob* >( sender() );
|
||||
|
||||
QID qid = job->property( "qid" ).toString();
|
||||
|
||||
if ( job->error() )
|
||||
{
|
||||
eval = QString( "resolve( '%1', '%2', '%3', '%4' )" )
|
||||
.arg( JSAccount::escape( query->id() ) )
|
||||
.arg( JSAccount::escape( query->queryTrack()->artist() ) )
|
||||
.arg( JSAccount::escape( query->queryTrack()->album() ) )
|
||||
.arg( JSAccount::escape( query->queryTrack()->track() ) );
|
||||
Tomahawk::Pipeline::instance()->reportError( qid, this );
|
||||
}
|
||||
else
|
||||
{
|
||||
eval = QString( "search( '%1', '%2' )" )
|
||||
.arg( JSAccount::escape( query->id() ) )
|
||||
.arg( JSAccount::escape( query->fullTextQuery() ) );
|
||||
|
||||
QList< Tomahawk::result_ptr > results = scriptAccount()->parseResultVariantList( data.value( "tracks" ).toList() );
|
||||
|
||||
foreach( const result_ptr& result, results )
|
||||
{
|
||||
result->setResolvedByResolver( this );
|
||||
result->setFriendlySource( name() );
|
||||
}
|
||||
|
||||
Tomahawk::Pipeline::instance()->reportResults( qid, this, results );
|
||||
}
|
||||
|
||||
QVariantMap m = callOnResolver( eval ).toMap();
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolver::stop()
|
||||
{
|
||||
Q_D( JSResolver );
|
||||
|
||||
d->stopped = true;
|
||||
d->resolverHelper->stop();
|
||||
|
||||
scriptAccount()->stop();
|
||||
|
||||
@@ -433,7 +402,7 @@ JSResolver::loadUi()
|
||||
{
|
||||
Q_D( JSResolver );
|
||||
|
||||
QVariantMap m = callOnResolver( "getConfigUi()" ).toMap();
|
||||
QVariantMap m = scriptObject()->syncInvoke( "getConfigUi" ).toMap();
|
||||
|
||||
bool compressed = m.value( "compressed", "false" ).toBool();
|
||||
qDebug() << "Resolver has a preferences widget! compressed?" << compressed;
|
||||
@@ -485,7 +454,7 @@ JSResolver::saveConfig()
|
||||
// qDebug() << Q_FUNC_INFO << saveData;
|
||||
|
||||
d->resolverHelper->setResolverConfig( saveData.toMap() );
|
||||
callOnResolver( "saveUserConfig()" );
|
||||
scriptObject()->syncInvoke( "saveUserConfig" );
|
||||
}
|
||||
|
||||
|
||||
@@ -516,39 +485,18 @@ JSResolver::onCapabilitiesChanged( Tomahawk::ExternalResolver::Capabilities capa
|
||||
}
|
||||
|
||||
|
||||
QVariantMap
|
||||
JSResolver::resolverSettings()
|
||||
{
|
||||
return callOnResolver( "settings" ).toMap();
|
||||
}
|
||||
|
||||
|
||||
QVariantMap
|
||||
JSResolver::resolverUserConfig()
|
||||
{
|
||||
return callOnResolver( "getUserConfig()" ).toMap();
|
||||
return scriptObject()->syncInvoke( "getUserConfig" ).toMap();
|
||||
}
|
||||
|
||||
|
||||
QVariantMap
|
||||
JSResolver::resolverInit()
|
||||
ScriptJob*
|
||||
JSResolver::getStreamUrl( const result_ptr& result )
|
||||
{
|
||||
return callOnResolver( "init()" ).toMap();
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
JSResolver::callOnResolver( const QString& scriptSource )
|
||||
{
|
||||
Q_D( JSResolver );
|
||||
|
||||
QString propertyName = scriptSource.split('(').first();
|
||||
|
||||
return d->scriptAccount->evaluateJavaScriptWithResult( QString(
|
||||
"if(Tomahawk.resolver.instance['_adapter_%1']) {"
|
||||
" Tomahawk.resolver.instance._adapter_%2;"
|
||||
"} else {"
|
||||
" Tomahawk.resolver.instance.%2"
|
||||
"}"
|
||||
).arg( propertyName ).arg( scriptSource ) );
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = result->url();
|
||||
|
||||
return scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -69,26 +70,26 @@ public:
|
||||
|
||||
void setIcon( const QPixmap& icon ) override;
|
||||
|
||||
bool canParseUrl( const QString& url, UrlType type ) override;
|
||||
|
||||
QVariantMap loadDataFromWidgets();
|
||||
|
||||
ScriptAccount* scriptAccount() const;
|
||||
|
||||
ScriptJob* getStreamUrl( const result_ptr& result ) override;
|
||||
|
||||
public slots:
|
||||
void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
void stop() override;
|
||||
void start() override;
|
||||
|
||||
// For UrlLookup
|
||||
void lookupUrl( const QString& url ) override;
|
||||
|
||||
signals:
|
||||
void stopped();
|
||||
|
||||
protected:
|
||||
QVariant callOnResolver( const QString& scriptSource );
|
||||
|
||||
private slots:
|
||||
void onResolveRequestDone(const QVariantMap& data);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -96,12 +97,16 @@ private:
|
||||
void onCapabilitiesChanged( Capabilities capabilities );
|
||||
|
||||
// encapsulate javascript calls
|
||||
QVariantMap resolverSettings();
|
||||
QVariantMap resolverUserConfig();
|
||||
QVariantMap resolverInit();
|
||||
|
||||
Q_DECLARE_PRIVATE( JSResolver )
|
||||
QScopedPointer<JSResolverPrivate> d_ptr;
|
||||
|
||||
// TODO: collection stuff, get rid of collection scriptcommands
|
||||
QString m_pendingUrl;
|
||||
Tomahawk::album_ptr m_pendingAlbum;
|
||||
private slots:
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection );
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
@@ -21,10 +21,6 @@
|
||||
|
||||
#include "JSResolverHelper.h"
|
||||
|
||||
#include "database/Database.h"
|
||||
#include "database/DatabaseImpl.h"
|
||||
#include "playlist/PlaylistTemplate.h"
|
||||
#include "playlist/XspfPlaylistTemplate.h"
|
||||
#include "resolvers/ScriptEngine.h"
|
||||
#include "network/Servent.h"
|
||||
#include "utils/Closure.h"
|
||||
@@ -51,6 +47,8 @@
|
||||
#include <QMap>
|
||||
#include <QWebFrame>
|
||||
#include <QLocale>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <taglib/asffile.h>
|
||||
#include <taglib/flacfile.h>
|
||||
#include <taglib/id3v2framefactory.h>
|
||||
@@ -76,11 +74,25 @@ JSResolverHelper::JSResolverHelper( const QString& scriptPath, JSResolver* paren
|
||||
: QObject( parent )
|
||||
, m_resolver( parent )
|
||||
, m_scriptPath( scriptPath )
|
||||
, m_urlCallbackIsAsync( false )
|
||||
, m_stopped( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::start()
|
||||
{
|
||||
m_stopped = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::stop()
|
||||
{
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
|
||||
QByteArray
|
||||
JSResolverHelper::readRaw( const QString& fileName )
|
||||
{
|
||||
@@ -140,55 +152,6 @@ JSResolverHelper::log( const QString& message )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::addTrackResults( const QVariantMap& results )
|
||||
{
|
||||
Q_ASSERT( results["results"].toMap().isEmpty() );
|
||||
|
||||
QList< Tomahawk::result_ptr > tracks = m_resolver->scriptAccount()->parseResultVariantList( results.value( "results" ).toList() );
|
||||
|
||||
foreach( const result_ptr& track, tracks )
|
||||
{
|
||||
track->setResolvedByResolver( m_resolver );
|
||||
track->setFriendlySource( m_resolver->name() );
|
||||
}
|
||||
|
||||
QString qid = results.value("qid").toString();
|
||||
|
||||
Tomahawk::Pipeline::instance()->reportResults( qid, m_resolver, tracks );
|
||||
}
|
||||
|
||||
|
||||
query_ptr
|
||||
JSResolverHelper::parseTrack( const QVariantMap& track )
|
||||
{
|
||||
QString title = track.value( "title" ).toString();
|
||||
QString artist = track.value( "artist" ).toString();
|
||||
QString album = track.value( "album" ).toString();
|
||||
if ( title.isEmpty() || artist.isEmpty() )
|
||||
{
|
||||
return query_ptr();
|
||||
}
|
||||
|
||||
Tomahawk::query_ptr query = Tomahawk::Query::get( artist, title, album );
|
||||
QString resultHint = track.value( "hint" ).toString();
|
||||
if ( !resultHint.isEmpty() )
|
||||
{
|
||||
query->setResultHint( resultHint );
|
||||
query->setSaveHTTPResultHint( true );
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
JSResolverHelper::instanceUUID()
|
||||
{
|
||||
return Tomahawk::Database::instance()->impl()->dbid();
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
JSResolverHelper::uuid() const
|
||||
{
|
||||
@@ -483,123 +446,13 @@ JSResolverHelper::currentCountry() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::addUrlResult( const QString& url, const QVariantMap& result )
|
||||
{
|
||||
// It may seem a bit weird, but currently no slot should do anything
|
||||
// more as we starting on a new URL and not task are waiting for it yet.
|
||||
m_pendingUrl = QString();
|
||||
m_pendingAlbum = album_ptr();
|
||||
|
||||
QString type = result.value( "type" ).toString();
|
||||
if ( type == "artist" )
|
||||
{
|
||||
QString name = result.value( "name" ).toString();
|
||||
Q_ASSERT( !name.isEmpty() );
|
||||
emit m_resolver->informationFound( url, Artist::get( name, true ).objectCast<QObject>() );
|
||||
}
|
||||
else if ( type == "album" )
|
||||
{
|
||||
QString name = result.value( "name" ).toString();
|
||||
QString artist = result.value( "artist" ).toString();
|
||||
album_ptr album = Album::get( Artist::get( artist, true ), name );
|
||||
m_pendingUrl = url;
|
||||
m_pendingAlbum = album;
|
||||
connect( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
|
||||
if ( !album->tracks().isEmpty() )
|
||||
{
|
||||
emit m_resolver->informationFound( url, album.objectCast<QObject>() );
|
||||
}
|
||||
}
|
||||
else if ( type == "track" )
|
||||
{
|
||||
Tomahawk::query_ptr query = parseTrack( result );
|
||||
if ( query.isNull() )
|
||||
{
|
||||
// A valid track result shoud have non-empty title and artist.
|
||||
tLog() << Q_FUNC_INFO << m_resolver->name() << "Got empty track information for " << url;
|
||||
emit m_resolver->informationFound( url, QSharedPointer<QObject>() );
|
||||
}
|
||||
else
|
||||
{
|
||||
emit m_resolver->informationFound( url, query.objectCast<QObject>() );
|
||||
}
|
||||
}
|
||||
else if ( type == "playlist" )
|
||||
{
|
||||
QString guid = result.value( "guid" ).toString();
|
||||
Q_ASSERT( !guid.isEmpty() );
|
||||
// Append nodeid to guid to make it globally unique.
|
||||
guid += instanceUUID();
|
||||
|
||||
// Do we already have this playlist loaded?
|
||||
{
|
||||
playlist_ptr playlist = Playlist::get( guid );
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
emit m_resolver->informationFound( url, playlist.objectCast<QObject>() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all information to build a new playlist but do not build it until we know,
|
||||
// if it is really handled as a playlist and not as a set of tracks.
|
||||
Tomahawk::source_ptr source = SourceList::instance()->getLocal();
|
||||
const QString title = result.value( "title" ).toString();
|
||||
const QString info = result.value( "info" ).toString();
|
||||
const QString creator = result.value( "creator" ).toString();
|
||||
QList<query_ptr> queries;
|
||||
foreach( QVariant track, result.value( "tracks" ).toList() )
|
||||
{
|
||||
query_ptr query = parseTrack( track.toMap() );
|
||||
if ( !query.isNull() )
|
||||
{
|
||||
queries << query;
|
||||
}
|
||||
}
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "Got playlist for " << url;
|
||||
playlisttemplate_ptr pltemplate( new PlaylistTemplate( source, guid, title, info, creator, false, queries ) );
|
||||
emit m_resolver->informationFound( url, pltemplate.objectCast<QObject>() );
|
||||
}
|
||||
else if ( type == "xspf-url" )
|
||||
{
|
||||
QString xspfUrl = result.value( "url" ).toString();
|
||||
Q_ASSERT( !xspfUrl.isEmpty() );
|
||||
QString guid = QString( "xspf-%1-%2" ).arg( xspfUrl.toUtf8().toBase64().constData() ).arg( instanceUUID() );
|
||||
|
||||
// Do we already have this playlist loaded?
|
||||
{
|
||||
playlist_ptr playlist = Playlist::get( guid );
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
emit m_resolver->informationFound( url, playlist.objectCast<QObject>() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get all information to build a new playlist but do not build it until we know,
|
||||
// if it is really handled as a playlist and not as a set of tracks.
|
||||
Tomahawk::source_ptr source = SourceList::instance()->getLocal();
|
||||
QSharedPointer<XspfPlaylistTemplate> pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) );
|
||||
NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ),
|
||||
this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ),
|
||||
url, pltemplate.objectCast<Tomahawk::PlaylistTemplate>() );
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "Got playlist for " << url;
|
||||
pltemplate->load();
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << m_resolver->name() << "No usable information found for " << url;
|
||||
emit m_resolver->informationFound( url, QSharedPointer<QObject>() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::nativeReportCapabilities( const QVariant& v )
|
||||
{
|
||||
if( m_stopped )
|
||||
return;
|
||||
|
||||
|
||||
bool ok;
|
||||
int intCap = v.toInt( &ok );
|
||||
Tomahawk::ExternalResolver::Capabilities capabilities;
|
||||
@@ -615,6 +468,9 @@ JSResolverHelper::nativeReportCapabilities( const QVariant& v )
|
||||
void
|
||||
JSResolverHelper::reportScriptJobResults( const QVariantMap& result )
|
||||
{
|
||||
if( m_stopped )
|
||||
return;
|
||||
|
||||
m_resolver->d_func()->scriptAccount->reportScriptJobResult( result );
|
||||
}
|
||||
|
||||
@@ -622,6 +478,9 @@ JSResolverHelper::reportScriptJobResults( const QVariantMap& result )
|
||||
void
|
||||
JSResolverHelper::registerScriptPlugin( const QString& type, const QString& objectId )
|
||||
{
|
||||
if( m_stopped )
|
||||
return;
|
||||
|
||||
m_resolver->d_func()->scriptAccount->registerScriptPlugin( type, objectId );
|
||||
}
|
||||
|
||||
@@ -629,28 +488,10 @@ JSResolverHelper::registerScriptPlugin( const QString& type, const QString& obje
|
||||
void
|
||||
JSResolverHelper::unregisterScriptPlugin( const QString& type, const QString& objectId )
|
||||
{
|
||||
m_resolver->d_func()->scriptAccount->unregisterScriptPlugin( type, objectId );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::tracksAdded( const QList<query_ptr>&, const ModelMode, const collection_ptr&)
|
||||
{
|
||||
// Check if we still are actively waiting
|
||||
if ( m_pendingAlbum.isNull() || m_pendingUrl.isNull() )
|
||||
if( m_stopped )
|
||||
return;
|
||||
|
||||
emit m_resolver->informationFound( m_pendingUrl, m_pendingAlbum.objectCast<QObject>() );
|
||||
m_pendingAlbum = album_ptr();
|
||||
m_pendingUrl = QString();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
emit m_resolver->informationFound( url, pltemplate.objectCast<QObject>() );
|
||||
m_resolver->d_func()->scriptAccount->unregisterScriptPlugin( type, objectId );
|
||||
}
|
||||
|
||||
|
||||
@@ -668,31 +509,6 @@ JSResolverHelper::accountId()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::addCustomUrlHandler( const QString& protocol,
|
||||
const QString& callbackFuncName,
|
||||
const QString& isAsynchronous )
|
||||
{
|
||||
m_urlCallbackIsAsync = ( isAsynchronous.toLower() == "true" );
|
||||
|
||||
std::function< void( const Tomahawk::result_ptr&, const QString&,
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > )> fac =
|
||||
std::bind( &JSResolverHelper::customIODeviceFactory, this,
|
||||
std::placeholders::_1, std::placeholders::_2,
|
||||
std::placeholders::_3 );
|
||||
Tomahawk::UrlHandler::registerIODeviceFactory( protocol, fac );
|
||||
|
||||
m_urlCallback = callbackFuncName;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::reportStreamUrl( const QString& qid, const QString& streamUrl )
|
||||
{
|
||||
reportStreamUrl( qid, streamUrl, QVariantMap() );
|
||||
}
|
||||
|
||||
|
||||
void JSResolverHelper::nativeAssert( bool assertion, const QString& message )
|
||||
{
|
||||
if ( !assertion )
|
||||
@@ -703,61 +519,6 @@ void JSResolverHelper::nativeAssert( bool assertion, const QString& message )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback )
|
||||
{
|
||||
//can be sync or async
|
||||
if ( m_urlCallbackIsAsync )
|
||||
{
|
||||
QString qid = uuid();
|
||||
QString getUrl = QString(
|
||||
"if(Tomahawk.resolver.instance['_adapter_%1']) {"
|
||||
" Tomahawk.resolver.instance._adapter_%1( {qid: '%2', url: '%3'} );"
|
||||
"} else {"
|
||||
" Tomahawk.resolver.instance.%1( {qid: '%2', url: '%3'} );"
|
||||
"}"
|
||||
).arg( m_urlCallback )
|
||||
.arg( qid )
|
||||
.arg( url );
|
||||
|
||||
m_streamCallbacks.insert( qid, callback );
|
||||
m_resolver->d_func()->scriptAccount->evaluateJavaScript( getUrl );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlCallback )
|
||||
.arg( url );
|
||||
|
||||
QString urlStr = m_resolver->d_func()->scriptAccount->evaluateJavaScriptWithResult( getUrl ).toString();
|
||||
|
||||
returnStreamUrl( urlStr, QMap<QString, QString>(), callback );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::reportStreamUrl( const QString& qid, const QString& streamUrl, const QVariantMap& headers )
|
||||
{
|
||||
if ( !m_streamCallbacks.contains( qid ) )
|
||||
return;
|
||||
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback = m_streamCallbacks.take( qid );
|
||||
|
||||
QMap<QString, QString> parsedHeaders;
|
||||
foreach ( const QString& key, headers.keys() )
|
||||
{
|
||||
Q_ASSERT_X( headers[key].canConvert( QVariant::String ), Q_FUNC_INFO, "Expected a Map of string for additional headers" );
|
||||
if ( headers[key].canConvert( QVariant::String ) )
|
||||
{
|
||||
parsedHeaders.insert( key, headers[key].toString() );
|
||||
}
|
||||
}
|
||||
|
||||
returnStreamUrl( streamUrl, parsedHeaders, callback );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::nativeRetrieveMetadata( int metadataId, const QString& url,
|
||||
const QString& mime_type, int sizehint,
|
||||
@@ -896,12 +657,27 @@ JSResolverHelper::nativeRetrieveMetadata( int metadataId, const QString& url,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSResolverHelper::invokeNativeScriptJob( int requestId, const QString& methodName, const QVariantMap& params )
|
||||
{
|
||||
if ( methodName == "httpRequest" ) {
|
||||
nativeAsyncRequest( requestId, params );
|
||||
} else {
|
||||
QVariantMap error;
|
||||
error["message"] = "NativeScriptJob methodName was not found";
|
||||
error["name"] = "method_was_not_found";
|
||||
|
||||
m_resolver->d_func()->scriptAccount->reportNativeScriptJobError( requestId, error );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::nativeAsyncRequest( const int requestId, const QString& url,
|
||||
const QVariantMap& headers,
|
||||
const QVariantMap& options )
|
||||
JSResolverHelper::nativeAsyncRequest( const int requestId, const QVariantMap& options )
|
||||
{
|
||||
QString url = options[ "url" ].toString();
|
||||
QVariantMap headers = options[ "headers" ].toMap();
|
||||
|
||||
QNetworkRequest req( url );
|
||||
foreach ( const QString& key, headers.keys() )
|
||||
{
|
||||
@@ -957,17 +733,16 @@ JSResolverHelper::nativeAsyncRequestDone( int requestId, NetworkReply* reply )
|
||||
map["status"] = reply->reply()->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
map["statusText"] = QString("%1 %2").arg( map["status"].toString() )
|
||||
.arg( reply->reply()->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString() );
|
||||
if (reply->reply()->hasRawHeader( "Content-Type" ))
|
||||
map["contentType"] = reply->reply()->rawHeader( "Content-Type" );
|
||||
|
||||
bool ok = false;
|
||||
QString json = QString::fromUtf8( TomahawkUtils::toJson( map, &ok ) );
|
||||
Q_ASSERT( ok );
|
||||
|
||||
QString javascript = QString( "Tomahawk.nativeAsyncRequestDone( %1, %2 );" )
|
||||
.arg( QString::number( requestId ) )
|
||||
.arg( json );
|
||||
m_resolver->d_func()->scriptAccount->evaluateJavaScript( javascript );
|
||||
QVariantMap responseHeaders;
|
||||
foreach( const QNetworkReply::RawHeaderPair& pair, reply->reply()->rawHeaderPairs() )
|
||||
{
|
||||
responseHeaders[ pair.first ] = pair.second;
|
||||
}
|
||||
map["responseHeaders"] = responseHeaders;
|
||||
|
||||
m_resolver->d_func()->scriptAccount->reportNativeScriptJobResult( requestId, map );
|
||||
}
|
||||
|
||||
|
||||
@@ -1143,43 +918,3 @@ JSResolverHelper::readdResolver()
|
||||
Pipeline::instance()->addResolver( m_resolver );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::returnStreamUrl( const QString& streamUrl, const QMap<QString, QString>& headers,
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback )
|
||||
{
|
||||
if ( streamUrl.isEmpty() || !( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) ) )
|
||||
{
|
||||
// Not an https? URL, so let Phonon handle it
|
||||
QSharedPointer< QIODevice > sp;
|
||||
callback( streamUrl, sp );
|
||||
}
|
||||
else
|
||||
{
|
||||
QUrl url = QUrl::fromEncoded( streamUrl.toUtf8() );
|
||||
QNetworkRequest req( url );
|
||||
foreach ( const QString& key, headers.keys() )
|
||||
{
|
||||
req.setRawHeader( key.toLatin1(), headers[key].toLatin1() );
|
||||
}
|
||||
tDebug() << "Creating a QNetworkReply with url:" << req.url().toString();
|
||||
NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( req ) );
|
||||
|
||||
NewClosure( reply, SIGNAL( finalUrlReached() ), this, SLOT( gotStreamUrl( IODeviceCallback, NetworkReply* )), callback, reply );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE( IODeviceCallback )
|
||||
|
||||
void
|
||||
JSResolverHelper::gotStreamUrl( std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback, NetworkReply* reply )
|
||||
{
|
||||
// std::functions cannot accept temporaries as parameters
|
||||
QSharedPointer< QIODevice > sp ( reply->reply(), &QObject::deleteLater );
|
||||
QString url = reply->reply()->url().toString();
|
||||
reply->disconnectFromReply();
|
||||
reply->deleteLater();
|
||||
|
||||
callback( url, sp );
|
||||
}
|
||||
|
@@ -54,6 +54,9 @@ public:
|
||||
*/
|
||||
void setResolverConfig( const QVariantMap& config );
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Get the instance unique account id for this resolver.
|
||||
*
|
||||
@@ -61,9 +64,6 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE QString accountId();
|
||||
|
||||
Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" );
|
||||
Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl );
|
||||
Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl, const QVariantMap& headers );
|
||||
|
||||
/**
|
||||
* Make Tomahawk assert the assertion is true, probably not to be used by resolvers directly
|
||||
@@ -89,20 +89,9 @@ public:
|
||||
int sizehint,
|
||||
const QVariantMap& options );
|
||||
|
||||
/**
|
||||
* Native handler for asynchronous HTTP requests.
|
||||
*
|
||||
* This handler shall only be used if we cannot achieve the request with
|
||||
* XMLHttpRequest as that would be more efficient.
|
||||
* Use cases are:
|
||||
* * Referer header: Stripped on MacOS and the specification says it
|
||||
* should be stripped
|
||||
*
|
||||
* INTERNAL USE ONLY!
|
||||
*/
|
||||
Q_INVOKABLE void nativeAsyncRequest( int requestId, const QString& url,
|
||||
const QVariantMap& headers,
|
||||
const QVariantMap& options );
|
||||
Q_INVOKABLE void invokeNativeScriptJob( int requestId,
|
||||
const QString& methodName,
|
||||
const QVariantMap& params );
|
||||
|
||||
/**
|
||||
* Lucene++ indices for JS resolvers
|
||||
@@ -122,18 +111,10 @@ public:
|
||||
Q_INVOKABLE void readdResolver();
|
||||
|
||||
|
||||
/**
|
||||
* INTERNAL USE ONLY!
|
||||
*/
|
||||
void customIODeviceFactory( const Tomahawk::result_ptr&, const QString& url,
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback ); // async
|
||||
|
||||
|
||||
public slots:
|
||||
QByteArray readRaw( const QString& fileName );
|
||||
QString readBase64( const QString& fileName );
|
||||
QString readCompressed( const QString& fileName );
|
||||
QString instanceUUID();
|
||||
QString uuid() const;
|
||||
int currentCountry() const;
|
||||
QString compress( const QString& data );
|
||||
@@ -142,10 +123,6 @@ public slots:
|
||||
void log( const QString& message );
|
||||
bool fakeEnv() { return false; }
|
||||
|
||||
void addTrackResults( const QVariantMap& results );
|
||||
|
||||
void addUrlResult( const QString& url, const QVariantMap& result );
|
||||
|
||||
void nativeReportCapabilities( const QVariant& capabilities );
|
||||
|
||||
void reportScriptJobResults( const QVariantMap& result );
|
||||
@@ -154,27 +131,20 @@ public slots:
|
||||
void unregisterScriptPlugin( const QString& type, const QString& objectId );
|
||||
|
||||
private slots:
|
||||
void gotStreamUrl( IODeviceCallback callback, NetworkReply* reply );
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection );
|
||||
void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate );
|
||||
void nativeAsyncRequestDone( int requestId, NetworkReply* reply );
|
||||
|
||||
private:
|
||||
Tomahawk::query_ptr parseTrack( const QVariantMap& track );
|
||||
void returnStreamUrl( const QString& streamUrl, const QMap<QString, QString>& headers,
|
||||
std::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback );
|
||||
|
||||
bool indexDataFromVariant( const QVariantMap& map, struct Tomahawk::IndexData& indexData );
|
||||
QVariantList searchInFuzzyIndex( const Tomahawk::query_ptr& query );
|
||||
|
||||
// native script jobs
|
||||
void nativeAsyncRequest( int requestId, const QVariantMap& options );
|
||||
|
||||
|
||||
QVariantMap m_resolverConfig;
|
||||
JSResolver* m_resolver;
|
||||
QString m_scriptPath, m_urlCallback, m_urlTranslator;
|
||||
QHash< QString, std::function< void( const QString&, QSharedPointer< QIODevice >& ) > > m_streamCallbacks;
|
||||
QHash< QString, std::function< void( const QString& ) > > m_translatorCallbacks;
|
||||
bool m_urlCallbackIsAsync;
|
||||
QString m_pendingUrl;
|
||||
Tomahawk::album_ptr m_pendingAlbum;
|
||||
QString m_scriptPath;
|
||||
bool m_stopped;
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
@@ -17,10 +17,31 @@
|
||||
*/
|
||||
#include "Resolver.h"
|
||||
|
||||
#include "../resolvers/SyncScriptJob.h"
|
||||
#include "../Result.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
|
||||
Tomahawk::Resolver::Resolver( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
Tomahawk::Resolver::icon( const QSize& ) const
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ScriptJob*
|
||||
Tomahawk::Resolver::getStreamUrl( const result_ptr& result )
|
||||
{
|
||||
QVariantMap data;
|
||||
data[ "url" ] = result->url();
|
||||
|
||||
return new SyncScriptJob( data );
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#ifndef RESOLVER_H
|
||||
#define RESOLVER_H
|
||||
|
||||
#include "../ResultProvider.h"
|
||||
#include "Typedefs.h"
|
||||
#include "DllMacro.h"
|
||||
|
||||
@@ -36,21 +35,23 @@
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
class ScriptJob;
|
||||
|
||||
class DLLEXPORT Resolver : public QObject, public ResultProvider
|
||||
class DLLEXPORT Resolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Resolver() {}
|
||||
Resolver( QObject* parent = nullptr );
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QPixmap icon( const QSize& size ) const;
|
||||
|
||||
virtual unsigned int weight() const = 0;
|
||||
virtual unsigned int timeout() const = 0;
|
||||
|
||||
virtual QPixmap icon( const QSize& size ) const override;
|
||||
|
||||
public slots:
|
||||
virtual void resolve( const Tomahawk::query_ptr& query ) = 0;
|
||||
virtual ScriptJob* getStreamUrl( const result_ptr& result );
|
||||
};
|
||||
|
||||
} //ns
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2014-2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../utils/Logger.h"
|
||||
#include "../Typedefs.h"
|
||||
|
||||
#include "plugins/ScriptLinkParserPluginFactory.h"
|
||||
#include "plugins/ScriptCollectionFactory.h"
|
||||
#include "plugins/ScriptInfoPluginFactory.h"
|
||||
|
||||
@@ -44,6 +45,7 @@ ScriptAccount::ScriptAccount( const QString& name )
|
||||
: QObject()
|
||||
, m_name( name )
|
||||
, m_stopped( true )
|
||||
, m_linkParserPluginFactory( new ScriptLinkParserPluginFactory() )
|
||||
, m_collectionFactory( new ScriptCollectionFactory() )
|
||||
, m_infoPluginFactory( new ScriptInfoPluginFactory() )
|
||||
{
|
||||
@@ -52,6 +54,7 @@ ScriptAccount::ScriptAccount( const QString& name )
|
||||
|
||||
ScriptAccount::~ScriptAccount()
|
||||
{
|
||||
delete m_linkParserPluginFactory;
|
||||
delete m_collectionFactory;
|
||||
delete m_infoPluginFactory;
|
||||
}
|
||||
@@ -62,6 +65,7 @@ ScriptAccount::start()
|
||||
{
|
||||
m_stopped = false;
|
||||
|
||||
m_linkParserPluginFactory->addAllPlugins();
|
||||
m_collectionFactory->addAllPlugins();
|
||||
m_infoPluginFactory->addAllPlugins();
|
||||
}
|
||||
@@ -72,6 +76,7 @@ ScriptAccount::stop()
|
||||
{
|
||||
m_stopped = true;
|
||||
|
||||
m_linkParserPluginFactory->removeAllPlugins();
|
||||
m_collectionFactory->removeAllPlugins();
|
||||
m_infoPluginFactory->removeAllPlugins();
|
||||
}
|
||||
@@ -193,7 +198,11 @@ ScriptAccount::unregisterScriptPlugin( const QString& type, const QString& objec
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type == "collection" )
|
||||
if( type == "linkParser" )
|
||||
{
|
||||
m_linkParserPluginFactory->unregisterPlugin( object );
|
||||
}
|
||||
else if ( type == "collection" )
|
||||
{
|
||||
m_collectionFactory->unregisterPlugin( object );
|
||||
}
|
||||
@@ -231,6 +240,10 @@ ScriptAccount::scriptPluginFactory( const QString& type, const scriptobject_ptr&
|
||||
ScriptLinkGeneratorPlugin* lgp = new ScriptLinkGeneratorPlugin( object );
|
||||
Utils::LinkGenerator::instance()->addPlugin( lgp );
|
||||
}
|
||||
else if( type == "linkParser" )
|
||||
{
|
||||
m_linkParserPluginFactory->registerPlugin( object, this );
|
||||
}
|
||||
else if ( type == "infoPlugin" )
|
||||
{
|
||||
m_infoPluginFactory->registerPlugin( object, this );
|
||||
@@ -326,21 +339,6 @@ ScriptAccount::parseResultVariantList( const QVariantList& reslist )
|
||||
}
|
||||
rp->setDownloadFormats( fl );
|
||||
|
||||
// find collection
|
||||
const QString collectionId = m.value( "collectionId" ).toString();
|
||||
if ( !collectionId.isEmpty() )
|
||||
{
|
||||
if ( scriptCollection( collectionId ).isNull() )
|
||||
{
|
||||
tLog() << "Resolver returned invalid collection id";
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
rp->setResolvedByCollection( scriptCollection( collectionId ) );
|
||||
}
|
||||
}
|
||||
|
||||
results << rp;
|
||||
}
|
||||
|
||||
@@ -348,8 +346,29 @@ ScriptAccount::parseResultVariantList( const QVariantList& reslist )
|
||||
}
|
||||
|
||||
|
||||
QSharedPointer< ScriptCollection >
|
||||
ScriptAccount::scriptCollection( const QString& id ) const
|
||||
ScriptJob*
|
||||
ScriptAccount::resolve( const scriptobject_ptr& scriptObject, const query_ptr& query, const QString& resolveType )
|
||||
{
|
||||
return m_collectionFactory->scriptPlugins().value( id );
|
||||
ScriptJob* job = nullptr;
|
||||
if ( !query->isFullTextQuery() )
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["artist"] = query->queryTrack()->artist();
|
||||
arguments["album"] = query->queryTrack()->album();
|
||||
arguments["track"] = query->queryTrack()->track();
|
||||
arguments["type"] = resolveType;
|
||||
|
||||
job = scriptObject->invoke( "resolve", arguments );
|
||||
}
|
||||
else
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["query"] = query->fullTextQuery();
|
||||
arguments["type"] = resolveType;
|
||||
job = scriptObject->invoke( "search", arguments );
|
||||
}
|
||||
|
||||
job->setProperty( "qid", query->id() );
|
||||
|
||||
return job;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2014-2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -39,6 +39,7 @@ namespace Tomahawk {
|
||||
|
||||
class ScriptObject;
|
||||
class ScriptJob;
|
||||
class ScriptLinkParserPluginFactory;
|
||||
class ScriptCollectionFactory;
|
||||
class ScriptInfoPluginFactory;
|
||||
|
||||
@@ -65,18 +66,20 @@ public:
|
||||
|
||||
ScriptJob* invoke( const scriptobject_ptr& scriptObject, const QString& methodName, const QVariantMap& arguments );
|
||||
virtual QVariant syncInvoke( const scriptobject_ptr& scriptObject, const QString& methodName, const QVariantMap& arguments ) = 0;
|
||||
|
||||
virtual void startJob( ScriptJob* scriptJob ) = 0;
|
||||
|
||||
void reportScriptJobResult( const QVariantMap& result );
|
||||
void registerScriptPlugin( const QString& type, const QString& objectId );
|
||||
void unregisterScriptPlugin( const QString& type, const QString& objectId );
|
||||
|
||||
virtual void reportNativeScriptJobResult( int resultId, const QVariantMap& result ) = 0;
|
||||
virtual void reportNativeScriptJobError( int resultId, const QVariantMap& error ) = 0;
|
||||
|
||||
virtual void scriptPluginFactory( const QString& type, const scriptobject_ptr& object );
|
||||
|
||||
// helpers
|
||||
QList< Tomahawk::result_ptr > parseResultVariantList( const QVariantList& reslist );
|
||||
|
||||
QSharedPointer< ScriptCollection > scriptCollection( const QString& id ) const;
|
||||
ScriptJob* resolve( const scriptobject_ptr& scriptObject, const query_ptr& query, const QString& resolveType );
|
||||
|
||||
private slots:
|
||||
void onJobDeleted( const QString& jobId );
|
||||
@@ -92,6 +95,7 @@ private: // TODO: pimple, might be renamed before tho
|
||||
QHash< QString, scriptobject_ptr > m_objects;
|
||||
|
||||
// port to QScopedPointer when pimple'd
|
||||
ScriptLinkParserPluginFactory* m_linkParserPluginFactory;
|
||||
ScriptCollectionFactory* m_collectionFactory;
|
||||
ScriptInfoPluginFactory* m_infoPluginFactory;
|
||||
};
|
||||
|
@@ -26,7 +26,10 @@
|
||||
#include "resolvers/ScriptCommand_AllArtists.h"
|
||||
#include "resolvers/ScriptCommand_AllAlbums.h"
|
||||
#include "resolvers/ScriptCommand_AllTracks.h"
|
||||
#include "resolvers/ScriptJob.h"
|
||||
#include "ScriptAccount.h"
|
||||
#include "Result.h"
|
||||
#include "Pipeline.h"
|
||||
|
||||
#include <QImageReader>
|
||||
#include <QPainter>
|
||||
@@ -223,6 +226,15 @@ void ScriptCollection::parseMetaData()
|
||||
return parseMetaData( readMetaData() );
|
||||
}
|
||||
|
||||
ScriptJob*
|
||||
ScriptCollection::getStreamUrl( const result_ptr& result )
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = result->url();
|
||||
|
||||
return scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCollection::parseMetaData( const QVariantMap& metadata )
|
||||
@@ -326,3 +338,58 @@ ScriptCollection::onIconFetched()
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
ScriptCollection::timeout() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
ScriptCollection::weight() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCollection::resolve( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
ScriptJob* job = scriptAccount()->resolve( scriptObject(), query, "collection" );
|
||||
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onResolveRequestDone( QVariantMap ) ) );
|
||||
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCollection::onResolveRequestDone( const QVariantMap& data )
|
||||
{
|
||||
Q_ASSERT( QThread::currentThread() == thread() );
|
||||
|
||||
ScriptJob* job = qobject_cast< ScriptJob* >( sender() );
|
||||
|
||||
QID qid = job->property( "qid" ).toString();
|
||||
|
||||
if ( job->error() )
|
||||
{
|
||||
Tomahawk::Pipeline::instance()->reportError( qid, this );
|
||||
}
|
||||
else
|
||||
{
|
||||
QList< Tomahawk::result_ptr > results = scriptAccount()->parseResultVariantList( data.value( "tracks" ).toList() );
|
||||
|
||||
foreach( const result_ptr& result, results )
|
||||
{
|
||||
result->setResolvedByCollection( weakRef().toStrongRef() );
|
||||
result->setFriendlySource( prettyName() );
|
||||
}
|
||||
|
||||
Tomahawk::Pipeline::instance()->reportResults( qid, this, results );
|
||||
}
|
||||
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
@@ -91,8 +91,15 @@ public:
|
||||
void parseMetaData();
|
||||
void parseMetaData( const QVariantMap& metadata );
|
||||
|
||||
// Resolver interface
|
||||
unsigned int weight() const override;
|
||||
unsigned int timeout() const override;
|
||||
void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
ScriptJob* getStreamUrl( const result_ptr& result ) override;
|
||||
|
||||
private slots:
|
||||
void onIconFetched();
|
||||
void onResolveRequestDone( const QVariantMap& data );
|
||||
|
||||
private:
|
||||
ScriptAccount* m_scriptAccount;
|
||||
|
@@ -34,7 +34,6 @@ signals:
|
||||
virtual void done() = 0;
|
||||
|
||||
protected:
|
||||
friend class ScriptCommandQueue;
|
||||
virtual void exec() = 0;
|
||||
virtual void reportFailure() = 0;
|
||||
};
|
||||
|
@@ -1,107 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptCommandQueue.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QMutex>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
ScriptCommandQueue::ScriptCommandQueue( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_timer( new QTimer( this ) )
|
||||
{
|
||||
m_timer->setSingleShot( true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommandQueue::enqueue( const QSharedPointer< ScriptCommand >& req )
|
||||
{
|
||||
QMutexLocker locker( &m_mutex );
|
||||
m_queue.append( req );
|
||||
locker.unlock();
|
||||
|
||||
if ( m_queue.count() == 1 )
|
||||
nextCommand();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommandQueue::nextCommand()
|
||||
{
|
||||
if ( m_queue.isEmpty() )
|
||||
return;
|
||||
|
||||
QSharedPointer< ScriptCommand > req = m_queue.first();
|
||||
|
||||
connect( req.data(), SIGNAL( done() ),
|
||||
this, SLOT( onCommandDone() ) );
|
||||
connect( m_timer, SIGNAL( timeout() ),
|
||||
this, SLOT( onTimeout() ) );
|
||||
|
||||
m_timer->start( 20000 );
|
||||
|
||||
req->exec();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommandQueue::onCommandDone()
|
||||
{
|
||||
if ( m_queue.isEmpty() || !m_timer->isActive() ) //the timeout already happened or some other weird thing
|
||||
return; //nothing to do here
|
||||
|
||||
m_timer->stop();
|
||||
|
||||
QMutexLocker locker( &m_mutex );
|
||||
const QSharedPointer< ScriptCommand > req = m_queue.first();
|
||||
m_queue.removeAll( req );
|
||||
locker.unlock();
|
||||
|
||||
disconnect( req.data(), SIGNAL( done() ),
|
||||
this, SLOT( onCommandDone() ) );
|
||||
disconnect( m_timer, SIGNAL( timeout() ),
|
||||
this, SLOT( onTimeout() ) );
|
||||
|
||||
if ( !m_queue.isEmpty() )
|
||||
nextCommand();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommandQueue::onTimeout()
|
||||
{
|
||||
m_timer->stop();
|
||||
|
||||
QMutexLocker locker( &m_mutex );
|
||||
const QSharedPointer< ScriptCommand > req = m_queue.first();
|
||||
m_queue.removeAll( req );
|
||||
locker.unlock();
|
||||
|
||||
req->reportFailure();
|
||||
|
||||
disconnect( req.data(), SIGNAL( done() ),
|
||||
this, SLOT( onCommandDone() ) );
|
||||
disconnect( m_timer, SIGNAL( timeout() ),
|
||||
this, SLOT( onTimeout() ) );
|
||||
|
||||
if ( !m_queue.isEmpty() )
|
||||
nextCommand();
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTCOMMANDQUEUE_H
|
||||
#define SCRIPTCOMMANDQUEUE_H
|
||||
|
||||
#include "ScriptCommand.h"
|
||||
|
||||
#include <QQueue>
|
||||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
#include <QMetaType>
|
||||
#include <QMutex>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class ScriptCommandQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ScriptCommandQueue( QObject* parent = 0 );
|
||||
virtual ~ScriptCommandQueue() {}
|
||||
|
||||
void enqueue( const QSharedPointer< ScriptCommand >& req );
|
||||
|
||||
private slots:
|
||||
void nextCommand();
|
||||
void onCommandDone();
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
QQueue< QSharedPointer< ScriptCommand > > m_queue;
|
||||
QTimer* m_timer;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
||||
Q_DECLARE_METATYPE( QSharedPointer< Tomahawk::ScriptCommand > )
|
||||
|
||||
#endif // SCRIPTCOMMANDQUEUE_H
|
@@ -117,7 +117,7 @@ ScriptCommand_AllTracks::onTracksJobDone( const QVariantMap& result )
|
||||
QSharedPointer< ScriptCollection > collection = m_collection.objectCast< ScriptCollection >();
|
||||
Q_ASSERT( !collection.isNull() );
|
||||
|
||||
QList< Tomahawk::result_ptr > t = collection->scriptAccount()->parseResultVariantList( result[ "results"].toList() );
|
||||
QList< Tomahawk::result_ptr > t = collection->scriptAccount()->parseResultVariantList( result[ "tracks" ].toList() );
|
||||
|
||||
|
||||
QList< Tomahawk::query_ptr > queries;
|
||||
|
@@ -1,78 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptCommand_LookupUrl_p.h"
|
||||
|
||||
#include "PlaylistEntry.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
ScriptCommand_LookupUrl::ScriptCommand_LookupUrl( Tomahawk::ExternalResolver* resolver, const QString& url, QObject* parent )
|
||||
: ScriptCommand( parent )
|
||||
, d_ptr( new ScriptCommand_LookupUrlPrivate( this, resolver, url ) )
|
||||
{
|
||||
}
|
||||
|
||||
ScriptCommand_LookupUrl::~ScriptCommand_LookupUrl()
|
||||
{
|
||||
delete d_ptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommand_LookupUrl::enqueue()
|
||||
{
|
||||
Q_D( ScriptCommand_LookupUrl );
|
||||
d->resolver->enqueue( QSharedPointer< ScriptCommand >( this ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommand_LookupUrl::exec()
|
||||
{
|
||||
Q_D( ScriptCommand_LookupUrl );
|
||||
connect( d->resolver, SIGNAL( informationFound( QString , QSharedPointer<QObject> ) ),
|
||||
this, SLOT( onResolverDone( QString, QSharedPointer<QObject> ) ) );
|
||||
|
||||
d->resolver->lookupUrl( d->url );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommand_LookupUrl::reportFailure()
|
||||
{
|
||||
Q_D( ScriptCommand_LookupUrl );
|
||||
emit information( d->url, QSharedPointer<QObject>() );
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptCommand_LookupUrl::onResolverDone( const QString& url, const QSharedPointer<QObject>& _information )
|
||||
{
|
||||
Q_D( ScriptCommand_LookupUrl );
|
||||
|
||||
qDebug() << Q_FUNC_INFO << url << _information.isNull();
|
||||
if ( url != d->url )
|
||||
{
|
||||
// This data is not for us, skip.
|
||||
return;
|
||||
}
|
||||
emit information( d->url, _information );
|
||||
emit done();
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTCOMMAND_LOOKUPURL_H
|
||||
#define SCRIPTCOMMAND_LOOKUPURL_H
|
||||
|
||||
#include "ScriptCommand.h"
|
||||
|
||||
#include "DllMacro.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class ScriptCommand_LookupUrlPrivate;
|
||||
class ExternalResolver;
|
||||
|
||||
class DLLEXPORT ScriptCommand_LookupUrl : public ScriptCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ScriptCommand_LookupUrl( Tomahawk::ExternalResolver* resolver,
|
||||
const QString& url,
|
||||
QObject* parent = nullptr );
|
||||
virtual ~ScriptCommand_LookupUrl();
|
||||
|
||||
void enqueue();
|
||||
|
||||
signals:
|
||||
void information( const QString& url, const QSharedPointer<QObject>& variant );
|
||||
void done();
|
||||
|
||||
protected:
|
||||
void exec() override;
|
||||
void reportFailure() override;
|
||||
|
||||
private slots:
|
||||
void onResolverDone( const QString& url, const QSharedPointer<QObject>& information );
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( ScriptCommand_LookupUrl )
|
||||
ScriptCommand_LookupUrlPrivate* d_ptr;
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
||||
#endif // SCRIPTCOMMAND_LOOKUPURL_H
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,6 +40,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxy>
|
||||
#include <QTimer>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <shlwapi.h>
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -63,8 +64,6 @@ public:
|
||||
|
||||
void sendMessage( const QVariantMap& map );
|
||||
|
||||
bool canParseUrl( const QString&, UrlType ) Q_DECL_OVERRIDE { return false; }
|
||||
|
||||
signals:
|
||||
void terminated();
|
||||
void customMessage( const QString& msgType, const QVariantMap& msg );
|
||||
@@ -74,9 +73,6 @@ public slots:
|
||||
void resolve( const Tomahawk::query_ptr& query ) Q_DECL_OVERRIDE;
|
||||
void start() Q_DECL_OVERRIDE;
|
||||
|
||||
void lookupUrl( const QString& ) Q_DECL_OVERRIDE {}
|
||||
|
||||
|
||||
private slots:
|
||||
void readStderr();
|
||||
void readStdout();
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "SourceList.h"
|
||||
#include "../ScriptAccount.h"
|
||||
#include "../../Pipeline.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -29,12 +30,14 @@ void ScriptCollectionFactory::addPlugin( const QSharedPointer<ScriptCollection>&
|
||||
|
||||
collection->setOnline( true );
|
||||
SourceList::instance()->addScriptCollection( collection );
|
||||
Pipeline::instance()->addResolver( collection.data() );
|
||||
}
|
||||
|
||||
void ScriptCollectionFactory::removePlugin( const QSharedPointer<ScriptCollection>& collection ) const
|
||||
{
|
||||
collection->setOnline( false );
|
||||
SourceList::instance()->removeScriptCollection( collection );
|
||||
Pipeline::instance()->removeResolver( collection.data() );
|
||||
}
|
||||
|
||||
QSharedPointer< ScriptCollection > ScriptCollectionFactory::createPlugin( const scriptobject_ptr& object, ScriptAccount* scriptAccount )
|
||||
|
228
src/libtomahawk/resolvers/plugins/ScriptLinkParserPlugin.cpp
Normal file
228
src/libtomahawk/resolvers/plugins/ScriptLinkParserPlugin.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ScriptLinkParserPlugin_p.h"
|
||||
|
||||
#include "../ScriptJob.h"
|
||||
#include "../ScriptObject.h"
|
||||
#include "../../utils/Logger.h"
|
||||
#include "../ScriptAccount.h"
|
||||
|
||||
#include "../../database/Database.h"
|
||||
#include "../../database/DatabaseImpl.h"
|
||||
#include "../../SourceList.h"
|
||||
#include "../../Artist.h"
|
||||
#include "../../Album.h"
|
||||
#include "../../playlist/PlaylistTemplate.h"
|
||||
#include "../../playlist/XspfPlaylistTemplate.h"
|
||||
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
ScriptLinkParserPlugin::ScriptLinkParserPlugin( const scriptobject_ptr& scriptObject, ScriptAccount* account )
|
||||
: Utils::LinkParserPlugin()
|
||||
, ScriptPlugin( scriptObject )
|
||||
, d_ptr( new ScriptLinkParserPluginPrivate( this, scriptObject, account ) )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ScriptLinkParserPlugin::~ScriptLinkParserPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ScriptLinkParserPlugin::canParseUrl( const QString& url, Tomahawk::Utils::UrlType type ) const
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = url;
|
||||
arguments["type"] = (int) type;
|
||||
|
||||
return scriptObject()->syncInvoke( "canParseUrl", arguments ).toBool();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptLinkParserPlugin::lookupUrl( const QString& url ) const
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = url;
|
||||
Tomahawk::ScriptJob* job = scriptObject()->invoke( "lookupUrl", arguments );
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onLookupUrlRequestDone( QVariantMap ) ) );
|
||||
job->setProperty( "url", url );
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptLinkParserPlugin::onLookupUrlRequestDone( const QVariantMap& result )
|
||||
{
|
||||
Q_D( ScriptLinkParserPlugin );
|
||||
|
||||
sender()->deleteLater();
|
||||
|
||||
QString url = sender()->property( "url" ).toString();
|
||||
|
||||
tLog() << "ON LOOKUP URL REQUEST DONE" << url << result;
|
||||
|
||||
// It may seem a bit weird, but currently no slot should do anything
|
||||
// more as we starting on a new URL and not task are waiting for it yet.
|
||||
d->pendingUrl = QString();
|
||||
d->pendingAlbum = album_ptr();
|
||||
|
||||
Utils::UrlType type = (Utils::UrlType) result.value( "type" ).toInt();
|
||||
if ( type == Utils::UrlTypeArtist )
|
||||
{
|
||||
QString name = result.value( "name" ).toString();
|
||||
Q_ASSERT( !name.isEmpty() );
|
||||
emit informationFound( url, Artist::get( name, true ).objectCast<QObject>() );
|
||||
}
|
||||
else if ( type == Utils::UrlTypeAlbum )
|
||||
{
|
||||
QString name = result.value( "name" ).toString();
|
||||
QString artist = result.value( "artist" ).toString();
|
||||
album_ptr album = Album::get( Artist::get( artist, true ), name );
|
||||
d->pendingUrl = url;
|
||||
d->pendingAlbum = album;
|
||||
connect( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
|
||||
if ( !album->tracks().isEmpty() )
|
||||
{
|
||||
emit informationFound( url, album.objectCast<QObject>() );
|
||||
}
|
||||
}
|
||||
else if ( type == Utils::UrlTypeTrack )
|
||||
{
|
||||
Tomahawk::query_ptr query = parseTrack( result );
|
||||
if ( query.isNull() )
|
||||
{
|
||||
// A valid track result shoud have non-empty title and artist.
|
||||
tLog() << Q_FUNC_INFO << d->scriptAccount->name() << "Got empty track information for " << url;
|
||||
emit informationFound( url, QSharedPointer<QObject>() );
|
||||
}
|
||||
else
|
||||
{
|
||||
emit informationFound( url, query.objectCast<QObject>() );
|
||||
}
|
||||
}
|
||||
else if ( type == Utils::UrlTypePlaylist )
|
||||
{
|
||||
QString guid = result.value( "guid" ).toString();
|
||||
Q_ASSERT( !guid.isEmpty() );
|
||||
// Append nodeid to guid to make it globally unique.
|
||||
guid += instanceUUID();
|
||||
|
||||
// Do we already have this playlist loaded?
|
||||
{
|
||||
playlist_ptr playlist = Playlist::get( guid );
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
emit informationFound( url, playlist.objectCast<QObject>() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all information to build a new playlist but do not build it until we know,
|
||||
// if it is really handled as a playlist and not as a set of tracks.
|
||||
Tomahawk::source_ptr source = SourceList::instance()->getLocal();
|
||||
const QString title = result.value( "title" ).toString();
|
||||
const QString info = result.value( "info" ).toString();
|
||||
const QString creator = result.value( "creator" ).toString();
|
||||
QList<query_ptr> queries;
|
||||
foreach( QVariant track, result.value( "tracks" ).toList() )
|
||||
{
|
||||
query_ptr query = parseTrack( track.toMap() );
|
||||
if ( !query.isNull() )
|
||||
{
|
||||
queries << query;
|
||||
}
|
||||
}
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << d->scriptAccount->name() << "Got playlist for " << url;
|
||||
playlisttemplate_ptr pltemplate( new PlaylistTemplate( source, guid, title, info, creator, false, queries ) );
|
||||
emit informationFound( url, pltemplate.objectCast<QObject>() );
|
||||
}
|
||||
else if ( type == Utils::UrlTypeXspf )
|
||||
{
|
||||
QString xspfUrl = result.value( "url" ).toString();
|
||||
Q_ASSERT( !xspfUrl.isEmpty() );
|
||||
QString guid = QString( "xspf-%1-%2" ).arg( xspfUrl.toUtf8().toBase64().constData() ).arg( instanceUUID() );
|
||||
|
||||
// Do we already have this playlist loaded?
|
||||
{
|
||||
playlist_ptr playlist = Playlist::get( guid );
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
emit informationFound( url, playlist.objectCast<QObject>() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get all information to build a new playlist but do not build it until we know,
|
||||
// if it is really handled as a playlist and not as a set of tracks.
|
||||
Tomahawk::source_ptr source = SourceList::instance()->getLocal();
|
||||
QSharedPointer<XspfPlaylistTemplate> pltemplate( new XspfPlaylistTemplate( xspfUrl, source, guid ) );
|
||||
NewClosure( pltemplate, SIGNAL( tracksLoaded( QList< Tomahawk::query_ptr > ) ),
|
||||
this, SLOT( pltemplateTracksLoadedForUrl( QString, Tomahawk::playlisttemplate_ptr ) ),
|
||||
url, pltemplate.objectCast<Tomahawk::PlaylistTemplate>() );
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << d->scriptAccount->name() << "Got playlist for " << url;
|
||||
pltemplate->load();
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << d->scriptAccount->name() << "No usable information found for " << url;
|
||||
emit informationFound( url, QSharedPointer<QObject>() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScriptLinkParserPlugin::pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
emit informationFound( url, pltemplate.objectCast<QObject>() );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
ScriptLinkParserPlugin::instanceUUID()
|
||||
{
|
||||
return Tomahawk::Database::instance()->impl()->dbid();
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::query_ptr
|
||||
ScriptLinkParserPlugin::parseTrack( const QVariantMap& track )
|
||||
{
|
||||
QString title = track.value( "track" ).toString();
|
||||
QString artist = track.value( "artist" ).toString();
|
||||
QString album = track.value( "album" ).toString();
|
||||
if ( title.isEmpty() || artist.isEmpty() )
|
||||
{
|
||||
return query_ptr();
|
||||
}
|
||||
|
||||
Tomahawk::query_ptr query = Tomahawk::Query::get( artist, title, album );
|
||||
QString resultHint = track.value( "hint" ).toString();
|
||||
if ( !resultHint.isEmpty() )
|
||||
{
|
||||
query->setResultHint( resultHint );
|
||||
query->setSaveHTTPResultHint( true );
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
61
src/libtomahawk/resolvers/plugins/ScriptLinkParserPlugin.h
Normal file
61
src/libtomahawk/resolvers/plugins/ScriptLinkParserPlugin.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOMAHAWK_SCRIPTLINKPARSERPLUGIN_H
|
||||
#define TOMAHAWK_SCRIPTLINKPARSERPLUGIN_H
|
||||
|
||||
#include "../../resolvers/ScriptPlugin.h"
|
||||
#include "../../utils/LinkParserPlugin.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class ScriptObject;
|
||||
class ScriptLinkParserPluginPrivate;
|
||||
|
||||
class DLLEXPORT ScriptLinkParserPlugin : public Utils::LinkParserPlugin, public ScriptPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScriptLinkParserPlugin( const scriptobject_ptr& scriptObject, ScriptAccount* account );
|
||||
virtual ~ScriptLinkParserPlugin();
|
||||
|
||||
bool canParseUrl( const QString& url, Tomahawk::Utils::UrlType type ) const override;
|
||||
void lookupUrl( const QString& url ) const override;
|
||||
|
||||
private slots:
|
||||
void onLookupUrlRequestDone( const QVariantMap& result );
|
||||
void pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate );
|
||||
|
||||
private:
|
||||
QString instanceUUID();
|
||||
static Tomahawk::query_ptr parseTrack( const QVariantMap& track );
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( ScriptLinkParserPlugin )
|
||||
QScopedPointer<ScriptLinkParserPluginPrivate> d_ptr;
|
||||
};
|
||||
|
||||
}; // ns: Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_SCRIPTLINKPARSERPLUGIN_H
|
@@ -0,0 +1,39 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ScriptLinkParserPluginFactory.h"
|
||||
|
||||
#include "../ScriptAccount.h"
|
||||
#include "../../utils/LinkParser.h"
|
||||
#include "../../utils/LinkParserPlugin.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
void ScriptLinkParserPluginFactory::addPlugin( const QSharedPointer <ScriptLinkParserPlugin >& plugin ) const
|
||||
{
|
||||
Tomahawk::Utils::LinkParser::instance()->addPlugin( plugin );
|
||||
}
|
||||
|
||||
void ScriptLinkParserPluginFactory::removePlugin( const QSharedPointer< ScriptLinkParserPlugin >& plugin ) const
|
||||
{
|
||||
Tomahawk::Utils::LinkParser::instance()->removePlugin( plugin );
|
||||
}
|
||||
|
||||
QSharedPointer< ScriptLinkParserPlugin > ScriptLinkParserPluginFactory::createPlugin( const scriptobject_ptr& object, ScriptAccount* scriptAccount )
|
||||
{
|
||||
return QSharedPointer< ScriptLinkParserPlugin >( new ScriptLinkParserPlugin( object, scriptAccount ) );
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef TOMAHAWK_SCRIPTLINKPARSERPLUGINFACTORY_H
|
||||
#define TOMAHAWK_SCRIPTLINKPARSERPLUGINFACTORY_H
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "ScriptLinkParserPlugin.h"
|
||||
#include "../ScriptPluginFactory.h"
|
||||
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
class ScriptAccount;
|
||||
|
||||
class DLLEXPORT ScriptLinkParserPluginFactory : public ScriptPluginFactory< ScriptLinkParserPlugin >
|
||||
{
|
||||
QSharedPointer< ScriptLinkParserPlugin > createPlugin( const scriptobject_ptr&, ScriptAccount* ) override;
|
||||
void addPlugin( const QSharedPointer< ScriptLinkParserPlugin >& scriptPlugin ) const override;
|
||||
void removePlugin( const QSharedPointer< ScriptLinkParserPlugin >& scriptPlugin ) const override;
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_SCRIPTLINKPARSERPLUGINFACTORY_H
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -16,33 +17,33 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTCOMMAND_LOOKUPURL_P_H
|
||||
#define SCRIPTCOMMAND_LOOKUPURL_P_H
|
||||
#ifndef TOMAHAWK_SCRIPTLINKGENERATORPLUGIN_P_H
|
||||
#define TOMAHAWK_SCRIPTLINKGENERATORPLUGIN_P_H
|
||||
|
||||
#include "ScriptCommand_LookupUrl.h"
|
||||
#include "ScriptLinkParserPlugin.h"
|
||||
|
||||
#include "ExternalResolver.h"
|
||||
|
||||
namespace Tomahawk
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class ScriptCommand_LookupUrlPrivate
|
||||
class ScriptLinkParserPluginPrivate
|
||||
{
|
||||
public:
|
||||
ScriptCommand_LookupUrlPrivate( ScriptCommand_LookupUrl* q, Tomahawk::ExternalResolver* _resolver, const QString& _url )
|
||||
ScriptLinkParserPluginPrivate( ScriptLinkParserPlugin* q, const scriptobject_ptr& scriptObject, ScriptAccount* scriptAccount )
|
||||
: q_ptr ( q )
|
||||
, url( _url )
|
||||
, resolver( _resolver )
|
||||
, scriptObject( scriptObject )
|
||||
, scriptAccount( scriptAccount )
|
||||
{
|
||||
}
|
||||
ScriptCommand_LookupUrl* q_ptr;
|
||||
Q_DECLARE_PUBLIC ( ScriptCommand_LookupUrl )
|
||||
ScriptLinkParserPlugin* q_ptr;
|
||||
Q_DECLARE_PUBLIC ( ScriptLinkParserPlugin )
|
||||
|
||||
private:
|
||||
QString url;
|
||||
Tomahawk::ExternalResolver* resolver;
|
||||
scriptobject_ptr scriptObject;
|
||||
ScriptAccount* scriptAccount;
|
||||
QString pendingUrl;
|
||||
album_ptr pendingAlbum;
|
||||
};
|
||||
|
||||
} // ns: Tomahawk
|
||||
|
||||
#endif // SCRIPTCOMMAND_LOOKUPURL_P_H
|
||||
#endif // TOMAHAWK_SCRIPTLINKGENERATORPLUGIN_P_H
|
122
src/libtomahawk/utils/LinkParser.cpp
Normal file
122
src/libtomahawk/utils/LinkParser.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2016, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LinkParser.h"
|
||||
|
||||
#include "TomahawkUtils.h"
|
||||
#include "Logger.h"
|
||||
#include "../resolvers/SyncScriptJob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Tomahawk::Utils;
|
||||
|
||||
LinkParser* LinkParser::s_instance = 0;
|
||||
|
||||
|
||||
LinkParser*
|
||||
LinkParser::instance()
|
||||
{
|
||||
if ( !s_instance )
|
||||
s_instance = new LinkParser;
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
||||
LinkParser::LinkParser( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LinkParser::~LinkParser()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LinkParser::addPlugin( const QSharedPointer< LinkParserPlugin >& plugin )
|
||||
{
|
||||
m_plugins.append( plugin );
|
||||
connect( plugin.data(), SIGNAL( informationFound( QString, QSharedPointer<QObject> ) ), SLOT( onInformationFound( QString, QSharedPointer<QObject> ) ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LinkParser::removePlugin( const QSharedPointer< LinkParserPlugin >& plugin )
|
||||
{
|
||||
if ( !plugin.isNull() )
|
||||
{
|
||||
disconnect( plugin.data(), 0, this, 0);
|
||||
|
||||
}
|
||||
|
||||
QMutableListIterator< QSharedPointer< LinkParserPlugin > > iter( m_plugins );
|
||||
while ( iter.hasNext() )
|
||||
{
|
||||
QSharedPointer< LinkParserPlugin > ptr = iter.next();
|
||||
if ( ptr.data() == plugin.data() || ptr.isNull() )
|
||||
{
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LinkParser::canParseUrl( const QString& url, UrlType type ) const
|
||||
{
|
||||
return !parserPluginsForUrl( url, type).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
QList< QSharedPointer< LinkParserPlugin > >
|
||||
LinkParser::parserPluginsForUrl( const QString& url, Tomahawk::Utils::UrlType type ) const
|
||||
{
|
||||
QList< QSharedPointer< LinkParserPlugin > > plugins;
|
||||
|
||||
foreach ( const QSharedPointer< LinkParserPlugin >& plugin, m_plugins )
|
||||
{
|
||||
if ( plugin->canParseUrl( url, type ) )
|
||||
{
|
||||
plugins.append( plugin );
|
||||
}
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LinkParser::lookupUrl( const QString& url, const QList< QSharedPointer < LinkParserPlugin > >& parserPlugins ) const
|
||||
{
|
||||
foreach ( const QSharedPointer< LinkParserPlugin >& plugin, parserPlugins )
|
||||
{
|
||||
if ( !plugin.isNull() )
|
||||
{
|
||||
plugin->lookupUrl( url );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LinkParser::onInformationFound( const QString& url, const QSharedPointer<QObject>& information )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << url;
|
||||
emit informationFound( url, information );
|
||||
}
|
69
src/libtomahawk/utils/LinkParser.h
Normal file
69
src/libtomahawk/utils/LinkParser.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef TOMAHAWK_UTILS_LINKPARSER_H
|
||||
#define TOMAHAWK_UTILS_LINKPARSER_H
|
||||
|
||||
#include "../resolvers/ScriptJob.h"
|
||||
#include "LinkParserPlugin.h"
|
||||
#include "UrlType.h"
|
||||
|
||||
#include "../DllMacro.h"
|
||||
#include "../Typedefs.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Tomahawk {
|
||||
|
||||
namespace Utils {
|
||||
|
||||
class LinkParserPlugin;
|
||||
|
||||
class DLLEXPORT LinkParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static LinkParser* instance();
|
||||
virtual ~LinkParser();
|
||||
|
||||
void addPlugin( const QSharedPointer< LinkParserPlugin >& plugin );
|
||||
void removePlugin( const QSharedPointer< LinkParserPlugin >& plugin );
|
||||
|
||||
bool canParseUrl( const QString& url, UrlType type ) const;
|
||||
QList< QSharedPointer < LinkParserPlugin > > parserPluginsForUrl( const QString& url, UrlType type ) const;
|
||||
void lookupUrl( const QString& url, const QList< QSharedPointer < LinkParserPlugin > >& parserPlugins = QList< QSharedPointer < LinkParserPlugin > >() ) const;
|
||||
|
||||
signals:
|
||||
void informationFound( const QString& url, const QSharedPointer<QObject>& information );
|
||||
|
||||
private slots:
|
||||
void onInformationFound( const QString& url, const QSharedPointer<QObject>& information );
|
||||
|
||||
private:
|
||||
explicit LinkParser( QObject* parent = 0 );
|
||||
QList< QSharedPointer < LinkParserPlugin > > m_plugins;
|
||||
|
||||
|
||||
static LinkParser* s_instance;
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_UTILS_LINKPARSER_H
|
24
src/libtomahawk/utils/LinkParserPlugin.cpp
Normal file
24
src/libtomahawk/utils/LinkParserPlugin.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "LinkParserPlugin.h"
|
||||
|
||||
#include "LinkParser.h"
|
||||
|
||||
Tomahawk::Utils::LinkParserPlugin::~LinkParserPlugin()
|
||||
{
|
||||
}
|
50
src/libtomahawk/utils/LinkParserPlugin.h
Normal file
50
src/libtomahawk/utils/LinkParserPlugin.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef TOMAHAWK_UTILS_LINKPARSERPLUGIN_H
|
||||
#define TOMAHAWK_UTILS_LINKPARSERPLUGIN_H
|
||||
|
||||
#include "../DllMacro.h"
|
||||
#include "../Typedefs.h"
|
||||
#include "UrlType.h"
|
||||
|
||||
namespace Tomahawk {
|
||||
|
||||
class ScriptJob;
|
||||
|
||||
namespace Utils {
|
||||
|
||||
class DLLEXPORT LinkParserPlugin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual ~LinkParserPlugin();
|
||||
|
||||
virtual bool canParseUrl( const QString& url, Tomahawk::Utils::UrlType type ) const = 0;
|
||||
virtual void lookupUrl( const QString& url ) const = 0;
|
||||
|
||||
signals:
|
||||
void informationFound( const QString&, const QSharedPointer<QObject>& );
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_UTILS_LINKPARSERPLUGIN_H
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2015 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -15,10 +15,5 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ResultProvider.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
ResultProvider::~ResultProvider()
|
||||
{
|
||||
}
|
||||
#include "UrlType.h"
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2015 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2016 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -15,28 +15,26 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef TOMAHAWK_RESULTPROVIDER_H
|
||||
#define TOMAHAWK_RESULTPROVIDER_H
|
||||
#ifndef TOMAHAWK_UTILS_URLTYPE_H
|
||||
#define TOMAHAWK_UTILS_URLTYPE_H
|
||||
|
||||
#include "DllMacro.h"
|
||||
namespace Tomahawk {
|
||||
|
||||
class QPixmap;
|
||||
class QString;
|
||||
class QSize;
|
||||
namespace Utils {
|
||||
|
||||
namespace Tomahawk
|
||||
enum UrlType
|
||||
{
|
||||
|
||||
class DLLEXPORT ResultProvider
|
||||
{
|
||||
public:
|
||||
virtual ~ResultProvider();
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QPixmap icon( const QSize& size ) const = 0;
|
||||
UrlTypeAny = 0x00,
|
||||
UrlTypePlaylist = 0x01,
|
||||
UrlTypeTrack = 0x02,
|
||||
UrlTypeAlbum = 0x04,
|
||||
UrlTypeArtist = 0x08,
|
||||
UrlTypeXspf = 0x10
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Utils
|
||||
} // namespace Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_RESULTPROVIDER_H
|
||||
#endif // TOMAHAWK_UTILS_URLTYPE_H
|
@@ -310,8 +310,9 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr result )
|
||||
connect( m_currentTrack->track().data(), SIGNAL( coverChanged() ), SLOT( onCoverUpdated() ) );
|
||||
connect( m_currentTrack->track().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) );
|
||||
|
||||
ui->artistLabel->setResult( result );
|
||||
setUpdatesEnabled( false );
|
||||
ui->trackLabel->setResult( result );
|
||||
ui->artistLabel->setResult( result );
|
||||
|
||||
const QString duration = TomahawkUtils::timeToString( result.data()->track()->duration() );
|
||||
ui->timeLabel->setFixedWidth( ui->timeLabel->fontMetrics().width( QString( duration.length(), QChar( '0' ) ) ) );
|
||||
@@ -370,6 +371,7 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr result )
|
||||
|
||||
setCover();
|
||||
setSocialActions();
|
||||
setUpdatesEnabled( true );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
set(TOMAHAWK_APPLICATION_TARGET "tomahahawk-bin")
|
||||
set(TOMAHAWK_APPLICATION_TARGET "tomahawk-bin")
|
||||
|
||||
include( ECMAddAppIcon )
|
||||
|
||||
@@ -146,8 +146,14 @@ IF( BUILD_GUI )
|
||||
ENDIF()
|
||||
|
||||
file( GLOB_RECURSE TOMAHAWK_ICONS "${CMAKE_SOURCE_DIR}/data/icons/*-tomahawk-icon.png" )
|
||||
if(APPLE)
|
||||
# OUTFILE is currently only supported in my branch, see https://git.reviewboard.kde.org/r/126303/
|
||||
# once merged (and released), we can remove this conditional usage
|
||||
ecm_add_app_icon(tomahawkSources ICONS ${TOMAHAWK_ICONS} OUTFILE "${TOMAHAWK_APPLICATION_NAME}")
|
||||
else()
|
||||
ecm_add_app_icon(tomahawkSources ICONS ${TOMAHAWK_ICONS})
|
||||
endif()
|
||||
|
||||
ecm_add_app_icon( tomahawkSources ICONS ${TOMAHAWK_ICONS} )
|
||||
|
||||
qt_add_resources( RC_SRCS "../../resources.qrc" )
|
||||
|
||||
|
@@ -96,12 +96,6 @@
|
||||
#endif
|
||||
#endif
|
||||
#include <shellapi.h>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,2,0)
|
||||
#include <windows.h>
|
||||
#ifndef THBN_CLICKED
|
||||
#define THBN_CLICKED 0x1800
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace Tomahawk;
|
||||
@@ -111,10 +105,6 @@ using namespace Accounts;
|
||||
TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
: QMainWindow( parent )
|
||||
, TomahawkUtils::DpiScaler( this )
|
||||
#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
, m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
|
||||
, m_taskbarList( 0 )
|
||||
#endif
|
||||
, ui( new Ui::TomahawkWindow )
|
||||
, m_searchWidget( 0 )
|
||||
, m_trayIcon( 0 )
|
||||
@@ -154,9 +144,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState ) ), SLOT( audioStateChanged( AudioState, AudioState ) ) );
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 2, 0 )
|
||||
setupWindowsButtons();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ( qApp->arguments().contains( "--debug" ) )
|
||||
@@ -537,61 +525,12 @@ TomahawkWindow::setupUpdateCheck()
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool
|
||||
void
|
||||
TomahawkWindow::setupWindowsButtons()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
|
||||
m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
|
||||
m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
|
||||
m_thumbButtons[TP_PREVIOUS].hIcon = thumbIcon(TomahawkUtils::PrevButton);
|
||||
m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
|
||||
m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[TP_NEXT].dwMask = dwMask;
|
||||
m_thumbButtons[TP_NEXT].iId = TP_NEXT;
|
||||
m_thumbButtons[TP_NEXT].hIcon = thumbIcon(TomahawkUtils::NextButton);
|
||||
m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[3].dwMask = dwMask;
|
||||
m_thumbButtons[3].iId = -1;
|
||||
m_thumbButtons[3].hIcon = 0;
|
||||
m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
|
||||
m_thumbButtons[3].szTip[0] = 0;
|
||||
|
||||
m_thumbButtons[TP_LOVE].dwMask = dwMask;
|
||||
m_thumbButtons[TP_LOVE].iId = TP_LOVE;
|
||||
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
|
||||
if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
|
||||
{
|
||||
hr = m_taskbarList->HrInit();
|
||||
if ( SUCCEEDED( hr ) )
|
||||
{
|
||||
hr = m_taskbarList->ThumbBarAddButtons( (HWND)winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_taskbarList->Release();
|
||||
m_taskbarList = 0;
|
||||
}
|
||||
}
|
||||
return SUCCEEDED( hr );
|
||||
#else
|
||||
m_taskbarList = new QWinThumbnailToolBar( this );
|
||||
m_taskbarList->setWindow( this->windowHandle() );
|
||||
updatePreview();
|
||||
|
||||
QWinThumbnailToolButton *back = new QWinThumbnailToolButton( m_taskbarList );
|
||||
back->setToolTip( tr( "Back" ) );
|
||||
@@ -625,26 +564,84 @@ TomahawkWindow::setupWindowsButtons()
|
||||
love->setInteractive( false );
|
||||
connect( love , SIGNAL( clicked() ) , this , SLOT( toggleLoved() ) );
|
||||
m_taskbarList->addButton(love);
|
||||
|
||||
return true;
|
||||
#endif//QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
}
|
||||
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
HICON
|
||||
TomahawkWindow::thumbIcon( TomahawkUtils::ImageType type )
|
||||
void
|
||||
TomahawkWindow::updatePreview()
|
||||
{
|
||||
static QMap<TomahawkUtils::ImageType,HICON> thumbIcons;
|
||||
if ( !thumbIcons.contains( type ) )
|
||||
{
|
||||
QPixmap pix ( TomahawkUtils::defaultPixmap(type , TomahawkUtils::Original, QSize( 40, 40 ) ) );
|
||||
thumbIcons[type] = pix.toWinHICON();
|
||||
const QSize size = QDesktopWidget().availableGeometry().size();
|
||||
const qreal margin = size.height() * 0.05;
|
||||
const QSize coverSize( size.height() - 2 * margin , size.height() - 2 * margin);
|
||||
QPixmap cover;
|
||||
QString title( qApp->applicationName() );
|
||||
if ( !m_currentTrack.isNull() ) {
|
||||
cover = m_currentTrack->track()->albumPtr()->cover( coverSize , false );
|
||||
title = tr( "%1<br><br><b>%2</b>", "track, artist name" ).arg( m_currentTrack->track()->track(), m_currentTrack->track()->artist() );
|
||||
}
|
||||
return thumbIcons[type];
|
||||
if ( cover.isNull() ) {
|
||||
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover , TomahawkUtils::Original, coverSize );
|
||||
}
|
||||
|
||||
QPixmap thumb( size );
|
||||
thumb.fill( QColor( "#FF004C" ) );
|
||||
|
||||
QPainter paint( &thumb );
|
||||
|
||||
QPen pen = paint.pen();
|
||||
pen.setColor( Qt::white );
|
||||
pen.setWidth( size.height() * 0.01 );
|
||||
paint.setPen( pen );
|
||||
|
||||
paint.drawPixmap(margin , margin , coverSize.width() , coverSize.height() , cover );
|
||||
paint.drawRect( margin , margin , coverSize.width() , coverSize.height() );
|
||||
paint.drawRect( 0 , 0 , size.width() , size.height() );
|
||||
|
||||
QTextDocument doc;
|
||||
|
||||
QFont font = paint.font();
|
||||
font.setPixelSize( size.height() * 0.1 );
|
||||
doc.setDefaultFont( font );
|
||||
|
||||
doc.setPageSize( QSize( size.width() - 2 * margin - coverSize.width() , size.height() - 2 * margin ) );
|
||||
doc.setHtml( QString( "<center><font color=\"white\">%1</font></center>" ).arg( title ));
|
||||
|
||||
paint.save();
|
||||
paint.translate( coverSize.width() + 2 * margin , ( size.height() - doc.size().height() ) / 2);
|
||||
|
||||
doc.drawContents( &paint );
|
||||
|
||||
paint.restore();
|
||||
|
||||
m_taskbarList->setIconicThumbnailPixmap( thumb );
|
||||
m_taskbarList->setIconicLivePreviewPixmap( thumb );
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
TomahawkWindow::updateWindowsLoveButton()
|
||||
{
|
||||
QWinThumbnailToolButton *love = m_taskbarList->buttons()[ TP_LOVE ];
|
||||
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() )
|
||||
{
|
||||
love->setInteractive(true);
|
||||
if ( AudioEngine::instance()->currentTrack()->track()->loved() )
|
||||
{
|
||||
love->setIcon(thumbIcon(TomahawkUtils::Loved));
|
||||
love->setToolTip( tr( "Unlove" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
love->setIcon( thumbIcon(TomahawkUtils::NotLoved) );
|
||||
love->setToolTip( tr( "Love" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
love->setInteractive(false);
|
||||
love->setIcon( thumbIcon(TomahawkUtils::NotLoved) );
|
||||
love->setToolTip( tr( "Love" ) );
|
||||
}
|
||||
}
|
||||
|
||||
QIcon
|
||||
TomahawkWindow::thumbIcon(TomahawkUtils::ImageType type)
|
||||
@@ -652,8 +649,6 @@ TomahawkWindow::thumbIcon(TomahawkUtils::ImageType type)
|
||||
return TomahawkUtils::defaultPixmap( type , TomahawkUtils::Original, QSize( 40, 40 ) );
|
||||
}
|
||||
|
||||
#endif//QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -844,51 +839,6 @@ TomahawkWindow::keyPressEvent( QKeyEvent* e )
|
||||
QMainWindow::keyPressEvent( e );
|
||||
}
|
||||
|
||||
|
||||
#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
bool
|
||||
TomahawkWindow::winEvent( MSG* msg, long* result )
|
||||
{
|
||||
Q_UNUSED(result);
|
||||
#define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
|
||||
|
||||
switch ( msg->message )
|
||||
{
|
||||
case WM_COMMAND:
|
||||
if ( HIWORD( msg->wParam ) == THBN_CLICKED )
|
||||
{
|
||||
switch ( TB_STATES( LOWORD( msg->wParam ) ) )
|
||||
{
|
||||
case TP_PREVIOUS:
|
||||
tLog() << TB_PRESSED << "Previous";
|
||||
AudioEngine::instance()->previous();
|
||||
break;
|
||||
case TP_PLAY_PAUSE:
|
||||
tLog() << TB_PRESSED << "Play/Pause";
|
||||
AudioEngine::instance()->playPause();
|
||||
break;
|
||||
case TP_NEXT:
|
||||
tLog() << TB_PRESSED << "Next";
|
||||
AudioEngine::instance()->next();
|
||||
break;
|
||||
case TP_LOVE:
|
||||
tLog() << TB_PRESSED << "Love";
|
||||
toggleLoved();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( msg->message == m_buttonCreatedID )
|
||||
return setupWindowsButtons();
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif//defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
|
||||
{
|
||||
@@ -896,48 +846,8 @@ TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
|
||||
#ifndef Q_OS_WIN
|
||||
Q_UNUSED(newState);
|
||||
#else
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
if ( m_taskbarList == 0 )
|
||||
return;
|
||||
switch ( newState )
|
||||
{
|
||||
case AudioEngine::Playing:
|
||||
{
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PauseButton);
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
updateWindowsLoveButton();
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case AudioEngine::Paused:
|
||||
{
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case AudioEngine::Stopped:
|
||||
{
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() )
|
||||
{
|
||||
disconnect( AudioEngine::instance()->currentTrack()->track().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
|
||||
}
|
||||
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
m_taskbarList->ThumbBarUpdateButtons( (HWND)winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
#else
|
||||
updatePreview();
|
||||
|
||||
QWinThumbnailToolButton *play = m_taskbarList->buttons()[ TP_PLAY_PAUSE ];
|
||||
switch ( newState )
|
||||
{
|
||||
@@ -946,7 +856,6 @@ TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
|
||||
play->setIcon( thumbIcon(TomahawkUtils::PauseButton) );
|
||||
play->setToolTip( tr( "Pause" ) );
|
||||
updateWindowsLoveButton();
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -976,57 +885,9 @@ TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
|
||||
default:
|
||||
return;
|
||||
}
|
||||
#endif//QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
#endif//Q_OS_WIN
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::updateWindowsLoveButton()
|
||||
{
|
||||
#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
if ( m_taskbarList == 0 )
|
||||
return;
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->track()->loved() )
|
||||
{
|
||||
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::Loved);
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
}
|
||||
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
|
||||
m_taskbarList->ThumbBarUpdateButtons( (HWND)winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
#elif defined(Q_OS_WIN)
|
||||
QWinThumbnailToolButton *love = m_taskbarList->buttons()[ TP_LOVE ];
|
||||
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() )
|
||||
{
|
||||
love->setInteractive(true);
|
||||
if ( AudioEngine::instance()->currentTrack()->track()->loved() )
|
||||
{
|
||||
love->setIcon(thumbIcon(TomahawkUtils::Loved));
|
||||
love->setToolTip( tr( "Unlove" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
love->setIcon( thumbIcon(TomahawkUtils::NotLoved) );
|
||||
love->setToolTip( tr( "Love" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
love->setInteractive(false);
|
||||
love->setIcon( thumbIcon(TomahawkUtils::NotLoved) );
|
||||
love->setToolTip( tr( "Love" ) );
|
||||
}
|
||||
#endif//defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::onHistoryBackAvailable( bool avail )
|
||||
{
|
||||
|
@@ -37,11 +37,9 @@
|
||||
#include <QToolButton>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <shobjidl.h>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 2, 0 )
|
||||
#include <QWinThumbnailToolBar>
|
||||
#include <QWinThumbnailToolButton>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
@@ -92,10 +90,6 @@ protected:
|
||||
|
||||
bool eventFilter( QObject* obj, QEvent* event );
|
||||
|
||||
#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
bool winEvent( MSG* message, long* result );
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void createStation();
|
||||
void createPlaylist();
|
||||
@@ -155,7 +149,11 @@ private slots:
|
||||
void toggleLoved();
|
||||
|
||||
void audioStateChanged( AudioState newState, AudioState oldState );
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void updateWindowsLoveButton();
|
||||
void updatePreview();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void loadSettings();
|
||||
@@ -173,16 +171,9 @@ private:
|
||||
void importPlaylist( const QString& url, bool autoUpdate );
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool setupWindowsButtons();
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
|
||||
const unsigned int m_buttonCreatedID;
|
||||
HICON thumbIcon(TomahawkUtils::ImageType type);
|
||||
ITaskbarList3* m_taskbarList;
|
||||
THUMBBUTTON m_thumbButtons[5];
|
||||
#else
|
||||
void setupWindowsButtons();
|
||||
QIcon thumbIcon(TomahawkUtils::ImageType type);
|
||||
QWinThumbnailToolBar *m_taskbarList;
|
||||
#endif
|
||||
enum TB_STATES{ TP_PREVIOUS = 0,TP_PLAY_PAUSE = 1,TP_NEXT = 2, TP_SPACE = 3, TP_LOVE = 4 };
|
||||
#endif
|
||||
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "sip/SipPlugin.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "Pipeline.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
@@ -123,6 +124,20 @@ DiagnosticsDialog::updateLogView()
|
||||
log.append( accountLog( account ) + "\n" );
|
||||
}
|
||||
|
||||
|
||||
log.append( "RESOLVERS:\n" );
|
||||
|
||||
|
||||
connect( Tomahawk::Pipeline::instance(), SIGNAL( resolverAdded( Tomahawk::Resolver* ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( Tomahawk::Pipeline::instance(), SIGNAL( resolverRemoved( Tomahawk::Resolver* ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
|
||||
const QList< Tomahawk::Resolver* > resolvers = Tomahawk::Pipeline::instance()->resolvers();
|
||||
foreach ( Tomahawk::Resolver* resolver, resolvers )
|
||||
{
|
||||
|
||||
log.append( resolver->name() + "\n" );
|
||||
}
|
||||
|
||||
ui->text->setText( log );
|
||||
}
|
||||
|
||||
|
@@ -366,8 +366,8 @@ Tomahawk::setupToolBarMac( TomahawkWindow* parent )
|
||||
[toolbar->nativeToolbar() setDisplayMode: NSToolbarDisplayModeIconOnly];
|
||||
[toolbar->nativeToolbar() setSizeMode: NSToolbarSizeModeSmall];
|
||||
|
||||
QMacToolBarItem* backItem = toolbar->addItem( ImageRegistry::instance()->pixmap( RESPATH "images/back.svg", QSize( 32, 32 ) ), QString( "Back" ) );
|
||||
QMacToolBarItem* forwardItem = toolbar->addItem( ImageRegistry::instance()->pixmap( RESPATH "images/forward.svg", QSize( 32, 32 ) ), QString( "Forward" ) );
|
||||
QMacToolBarItem* backItem = toolbar->addItem( ImageRegistry::instance()->pixmap( RESPATH "images/nav-back.svg", QSize( 32, 32 ) ), QString( "Back" ) );
|
||||
QMacToolBarItem* forwardItem = toolbar->addItem( ImageRegistry::instance()->pixmap( RESPATH "images/nav-forward.svg", QSize( 32, 32 ) ), QString( "Forward" ) );
|
||||
|
||||
QObject::connect( backItem, SIGNAL( activated() ), ViewManager::instance(), SLOT( historyBack() ) );
|
||||
QObject::connect( forwardItem, SIGNAL( activated() ), ViewManager::instance(), SLOT( historyForward() ) );
|
||||
@@ -381,6 +381,12 @@ Tomahawk::setupToolBarMac( TomahawkWindow* parent )
|
||||
searchField->parent = parent;
|
||||
[searchItem->nativeToolBarItem() setView: searchField];
|
||||
|
||||
NSSize nsirect = [searchField frame].size;
|
||||
nsirect.width = 250;
|
||||
[searchItem->nativeToolBarItem() setMinSize: nsirect];
|
||||
nsirect.width = 450;
|
||||
[searchItem->nativeToolBarItem() setMaxSize: nsirect];
|
||||
|
||||
QMacToolBarItem* spacerRightItem = toolbar->addItem( QIcon(), QString() );
|
||||
spacerRightItem->setStandardItem( QMacToolBarItem::FlexibleSpace );
|
||||
|
||||
|
@@ -538,7 +538,7 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
|
||||
|
||||
paintStandardItem( painter, optIndentation, index, count );
|
||||
}
|
||||
else if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage )
|
||||
else if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage || type == SourcesModel::RemovablePage )
|
||||
{
|
||||
if ( opt.state & QStyle::State_MouseOver )
|
||||
{
|
||||
@@ -668,7 +668,7 @@ SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QSt
|
||||
if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
|
||||
if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage )
|
||||
if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage || type == SourcesModel::RemovablePage )
|
||||
{
|
||||
SourceTreeItem* gpi = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
||||
Q_ASSERT( gpi );
|
||||
|
@@ -334,7 +334,15 @@ SourcesModel::appendPageItem( const QString& name, ViewPage* page, int sortValue
|
||||
page->pixmap(),
|
||||
std::bind( &ViewManager::showDynamicPage, ViewManager::instance(), name ),
|
||||
std::bind( &ViewManager::dynamicPageWidget, ViewManager::instance(), name ) );
|
||||
pageItem->setDeletable( page->isDeletable() );
|
||||
|
||||
if ( page->isDeletable() )
|
||||
{
|
||||
pageItem->setDeletable( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
pageItem->setRemovable( page->isRemovable() );
|
||||
}
|
||||
|
||||
if ( sortValue )
|
||||
{
|
||||
|
@@ -63,6 +63,7 @@ public:
|
||||
TemporaryPage = 7,
|
||||
LovedTracksPage = 10,
|
||||
DeletablePage = 15,
|
||||
RemovablePage = 16,
|
||||
|
||||
Collection = 14,
|
||||
ScriptCollection = 11,
|
||||
|
@@ -132,6 +132,18 @@ GenericPageItem::setDeletable( bool deletable )
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericPageItem::setRemovable( bool removable )
|
||||
{
|
||||
if ( removable )
|
||||
{
|
||||
setRowType( SourcesModel::RemovablePage );
|
||||
}
|
||||
else
|
||||
{
|
||||
setRowType( SourcesModel::GenericPage );
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GenericPageItem::peerSortValue() const
|
||||
|
@@ -43,6 +43,7 @@ public:
|
||||
virtual int peerSortValue() const; // How to sort relative to peers in the tree.
|
||||
virtual bool isBeingPlayed() const;
|
||||
|
||||
void setRemovable( bool removable );
|
||||
void setDeletable( bool deletable );
|
||||
void setText( const QString& text );
|
||||
void setSortValue( int value );
|
||||
|
@@ -91,7 +91,8 @@ public:
|
||||
const QString pixmapPath() const { return ( RESPATH "images/whatsnew.svg" ); }
|
||||
|
||||
bool addPageItem() const;
|
||||
bool isDeletable() const { return true; }
|
||||
bool isRemovable() const override { return true; }
|
||||
bool isDeletable() const override { return false; }
|
||||
void onItemDeleted();
|
||||
|
||||
int sortValue() { return 1; }
|
||||
|
2
thirdparty/libcrashreporter-qt
vendored
2
thirdparty/libcrashreporter-qt
vendored
Submodule thirdparty/libcrashreporter-qt updated: 0dc4a719ca...0287c3358a
Reference in New Issue
Block a user