1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-09 05:30:52 +02:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Dominik Schmidt
365c7b0e31 Get woah resolvers from synchrotron 2015-11-13 01:55:15 +01:00
Dominik Schmidt
9ae97e50ad Move moar stuff over to es6 foo 2015-11-13 01:55:15 +01:00
Dominik Schmidt
72dab1aae6 Move to new es6 based standalone resolvers 2015-11-13 01:54:32 +01:00
107 changed files with 1382 additions and 2382 deletions

View File

@@ -307,10 +307,11 @@ else()
message(STATUS "${CMAKE_CXX_COMPILER} does not support C++11, please use a
different compiler")
endif()
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR APPLE) AND LIBCPP_FOUND)
if(LIBCPP_FOUND AND APPLE)
tomahawk_add_cxx_flags( "-stdlib=libc++" )
endif()
macro_optional_find_package(Echonest 2.3.0)
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.3.0 is needed for dynamic playlists and the infosystem")
@@ -403,8 +404,12 @@ if( WIN32 )
endif( WIN32 )
if( WIN32 OR APPLE )
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 "" "")
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 "" "")
endif()
find_package(LIBVLC REQUIRED 2.1.0)

View File

@@ -6,16 +6,19 @@ 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})
@@ -29,6 +32,8 @@ int main(int argc, char *argv[]) {
HAVE_VLC_ALBUMARTIST)
find_package_handle_standard_args(LibVLC
REQUIRED_VARS LIBVLC_LIBRARY LIBVLC_INCLUDE_DIR
REQUIRED_VARS LIBVLC_LIBRARY LIBVLCCORE_LIBRARY LIBVLC_INCLUDE_DIR
VERSION_VAR LIBVLC_VERSION
)

View File

@@ -15,25 +15,21 @@
;-----------------------------------------------------------------------------
; Some paths.
;-----------------------------------------------------------------------------
!ifndef MINGW_ROOT
!define MINGW_ROOT "/usr/i686-w64-mingw32/sys-root/mingw"
!ifndef MING_PATH
!define MING_PATH "/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 MINGW_BIN "${MINGW_ROOT}/bin"
!define MINGW_LIB "${MINGW_ROOT}/lib"
!define MINGW_SHARE "${MINGW_ROOT}/share"
!define MING_BIN "${MING_PATH}/bin"
!define MING_LIB "${MING_PATH}/lib"
!define BUILD_PATH "@CMAKE_BINARY_DIR@"
!define SOURCE_PATH "@CMAKE_SOURCE_DIR@"
!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"
!define QT_DLL_PATH "${MING_BIN}"
!define SQLITE_DLL_PATH "${MING_LIB}/qt5/plugins/sqldrivers"
!define IMAGEFORMATS_DLL_PATH "${MING_LIB}/qt5/plugins/imageformats"
; We use official release plugins
; mingw32-vlc from obs misses a lot and has even broken ones probably
@@ -334,7 +330,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"
@@ -343,112 +339,96 @@ 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"
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 "${MINGW_BIN}\libsqlite3-0.dll"
;Boost fnord
File "${QT_DLL_PATH}\icuuc53.dll"
File "${QT_DLL_PATH}\icudata53.dll"
File "${QT_DLL_PATH}\icui18n53.dll"
;Qt platform plugins
SetOutPath "$INSTDIR\platforms"
File "${MINGW_LIB}/qt5/plugins/platforms/qwindows.dll"
SetOutPath "$INSTDIR"
;SQLite driver
SetOutPath "$INSTDIR\sqldrivers"
File "${SQLITE_DLL_PATH}\qsqlite.dll"
SetOutPath "$INSTDIR"
File "${MING_BIN}\libsqlite3-0.dll"
;Image plugins
SetOutPath "$INSTDIR\imageformats"
File "${IMAGEFORMATS_DLL_PATH}\qgif.dll"
File "${IMAGEFORMATS_DLL_PATH}\qjpeg.dll"
File "${IMAGEFORMATS_DLL_PATH}\qsvg.dll"
SetOutPath "$INSTDIR"
;Qt platform plugins
SetOutPath "$INSTDIR\platforms"
File "${MING_LIB}/qt5/plugins/platforms/qwindows.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"
;Image plugins
SetOutPath "$INSTDIR\imageformats"
File "${IMAGEFORMATS_DLL_PATH}\qgif.dll"
File "${IMAGEFORMATS_DLL_PATH}\qjpeg.dll"
File "${IMAGEFORMATS_DLL_PATH}\qsvg.dll"
SetOutPath "$INSTDIR"
;Cygwin/c++ stuff
File "${MINGW_BIN}\libgcc_s_sjlj-1.dll"
File "${MINGW_BIN}\libstdc++-6.dll"
;Cygwin/c++ stuff
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
File "${MING_BIN}\libstdc++-6.dll"
;VLC
File "${VLC_BIN}\libvlc.dll"
File "${VLC_BIN}\libvlccore.dll"
SetOutPath "$INSTDIR\plugins"
File /r "${VLC_PLUGIN_PATH}\*.dll"
SetOutPath "$INSTDIR"
;VLC
File "${VLC_BIN}\libvlc.dll"
File "${VLC_BIN}\libvlccore.dll"
SetOutPath "$INSTDIR\plugins"
File /r "${VLC_PLUGIN_PATH}\*.dll"
SetOutPath "$INSTDIR"
; Other
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"
; Other
File "${MING_BIN}\libtag.dll"
File "${MING_BIN}\libpng16-16.dll"
File "${MING_BIN}\libjpeg-8.dll"
File "${MING_BIN}\zlib1.dll"
; ANGLE
File "${MINGW_BIN}\D3DCompiler_43.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"
; GnuTLS
File "${MINGW_BIN}\libgnutls-28.dll"
File "${MINGW_BIN}\libtasn1-6.dll"
File "${MINGW_BIN}\libgmp-10.dll"
File "${MINGW_BIN}\libhogweed-4-1.dll"
File "${MINGW_BIN}\libintl-8.dll"
File "${MINGW_BIN}\libnettle-6-1.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"
; Snorenotify
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 "${MINGW_BIN}\libsnoregrowl++.dll"
File "${MINGW_BIN}\libsnoregrowl.dll"
; Snoregrowl
File "${MING_BIN}\libsnoregrowl++.dll"
File "${MING_BIN}\libsnoregrowl.dll"
; Jabber
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 "${MINGW_LIB}\qca-qt5\crypto\libqca-ossl.dll"
SetOutPath "$INSTDIR"
File "${MINGW_BIN}\libssl-10.dll"
File "${MINGW_BIN}\libcrypto-10.dll"
File "${MING_BIN}\libjreen-qt5.dll"
File "${MING_BIN}\libidn-11.dll"
File "${MING_BIN}\libgsasl-7.dll"
File "${MING_BIN}\libqca-qt5.dll"
SetOutPath "$INSTDIR\crypto"
File "${MING_LIB}\qca-qt5\crypto\libqca-ossl.dll"
SetOutPath "$INSTDIR"
File "${MING_BIN}\libssl-10.dll"
File "${MING_BIN}\libcrypto-10.dll"
; LucenePlusPlus
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"
; 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}\libqtsparkle-qt5.dll"
File "${MINGW_BIN}\libKF5Attica.dll"
File "${MING_BIN}\libqtsparkle-qt5.dll"
File "${MING_BIN}\libKF5Attica.dll"
SectionEnd
SectionGroup "Shortcuts"
@@ -463,7 +443,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}\Notification Settings.lnk" "$INSTDIR\snoresettings.exe" "-a ${APPLICATION_NAME}"
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_NAME}.exe"
!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"

View File

@@ -2,7 +2,7 @@ INCLUDE( InstallRequiredSystemLibraries )
SET( CPACK_PACKAGE_CONTACT "Dominik Schmidt <domme@tomahawk-player.org>" )
SET( CPACK_PACKAGE_FILE_NAME "${TOMAHAWK_TARGET_NAME}-${TOMAHAWK_VERSION}" ) # Package file name without extension. Also a directory of installer cmake-2.5.0-Linux-i686
SET( CPACK_PACKAGE_FILE_NAME "${TOMAHAWK_APPLICATION_NAME}-${TOMAHAWK_VERSION}" ) # Package file name without extension. Also a directory of installer cmake-2.5.0-Linux-i686
# CPACK_GENERATOR CPack generator to be used STGZ;TGZ;TZ
# CPACK_INCLUDE_TOPLEVEL_DIRECTORY Controls whether CPack adds a top-level directory, usually of the form ProjectName-Version-OS, to the top of package tree. 0 to disable, 1 to enable

View File

@@ -5,23 +5,23 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>@TOMAHAWK_APPLICATION_NAME@</string>
<string>Tomahawk</string>
<key>CFBundleIdentifier</key>
<string>@TOMAHAWK_APPLICATION_PACKAGE_NAME@</string>
<string>org.tomahawk-player.Tomahawk</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_BASE_TARGET_NAME@</string>
<string>tomahawk</string>
<key>CFBundleIconFile</key>
<string>@TOMAHAWK_APPLICATION_NAME@.icns</string>
<string>Tomahawk.icns</string>
<key>CFBundleName</key>
<string>@TOMAHAWK_APPLICATION_NAME@</string>
<string>Tomahawk</string>
<key>LSMinimumSystemVersion</key>
<string>10.7.0</string>
<key>NSPrincipalClass</key>
@@ -29,7 +29,7 @@
<key>NSHighResolutionCapable</key>
<true />
<key>SUFeedURL</key>
<string>@TOMAHAWK_SPARKLE_UPDATE_URL@</string>
<string>http://download.tomahawk-player.org/sparkle/update.php</string>
<key>SUPublicDSAKeyFile</key>
<string>sparkle_pub.pem</string>
<key>SUEnableSystemProfiling</key>

View File

@@ -4,10 +4,9 @@
#
################################################################################
TARGET_NAME="Tomahawk"
set -e
function header {
echo -e "\033[0;34m==>\033[0;0;1m $1 \033[0;0m"
}
@@ -32,28 +31,30 @@ CERT_SIGNER=$2
################################################################################
header "Fixing and copying libraries"
$ROOT/../admin/mac/macdeploy.py "${TARGET_NAME}.app" quiet
$ROOT/../admin/mac/macdeploy.py Tomahawk.app quiet
cd "${TARGET_NAME}.app"
cd Tomahawk.app
cp $ROOT/../admin/mac/qt.conf Contents/Resources/qt.conf
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"
cd ..
if [ -f ~/sign_step.sh ];
then
~/sign_step.sh "$CERT_SIGNER" "${TARGET_NAME}.app" || true
fi
# header "Copying Sparkle framework"
# cp -R /Library/Frameworks/Sparkle.framework Contents/Frameworks
header "Creating DMG"
$ROOT/../admin/mac/create-dmg.sh "${TARGET_NAME}.app"
mv "${TARGET_NAME}.dmg" "${TARGET_NAME}-$VERSION.dmg"
cd ..
header "Signing bundle"
# codesign -s "Developer ID Application: $CERT_SIGNER" -f -v ./Tomahawk.app
if [ -f ~/sign_step.sh ];
then
~/sign_step.sh "$CERT_SIGNER" "Tomahawk.app" || true
fi
$ROOT/../admin/mac/create-dmg.sh Tomahawk.app
mv Tomahawk.dmg Tomahawk-$VERSION.dmg
header "Creating signed Sparkle update"
# $ROOT/../admin/mac/sign_bundle.rb "${TARGET_NAME}" $VERSION ~/tomahawk_sparkle_privkey.pem
$ROOT/../admin/mac/sign_bundle.rb $VERSION ~/tomahawk_sparkle_privkey.pem
header "Done!"

View File

@@ -43,7 +43,7 @@ ln -s /Applications "$TMP/Applications"
cp -R "$IN" "$TMP"
# create
hdiutil makehybrid -hfs -hfs-volume-name "$NAME" -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg
hdiutil makehybrid -hfs -hfs-volume-name Tomahawk -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg
hdiutil convert -format UDZO -imagekey zlib-level=9 tmp.dmg -o "$OUT"
# cleanup

View File

@@ -22,170 +22,171 @@ 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/opt/vlc/lib', '/usr/local/Cellar/gettext/0.19.2/lib', '.']
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.19.2/lib', '.']
VLC_PLUGINS=[
'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',
'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',
#'libconverter_fixed_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',
'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',
#'libspdif_mixer_plugin.dylib',
#'libtrivial_mixer_plugin.dylib',
#'libaout_file_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',
'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',
#'libfake_plugin.dylib',
'libflac_plugin.dylib',
'codec/libflac_plugin.dylib',
#'libfluidsynth_plugin.dylib',
#'libinvmem_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',
'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',
#'libhotkeys_plugin.dylib',
#'libmotion_plugin.dylib',
#'libnetsync_plugin.dylib',
#'libsignals_plugin.dylib',
'libaiff_plugin.dylib',
'libasf_plugin.dylib',
'libau_plugin.dylib',
'demux/libaiff_plugin.dylib',
'demux/libasf_plugin.dylib',
'demux/libau_plugin.dylib',
#'libavformat_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',
'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',
#'libaudioscrobbler_plugin.dylib',
'libdummy_plugin.dylib',
'libexport_plugin.dylib',
'control/libdummy_plugin.dylib',
'misc/libexport_plugin.dylib',
#'libfreetype_plugin.dylib',
#'libgnutls_plugin.dylib',
'liblogger_plugin.dylib',
'liblua_plugin.dylib',
'misc/liblogger_plugin.dylib',
'lua/liblua_plugin.dylib',
#'libosd_parser_plugin.dylib',
#'libquartztext_plugin.dylib',
#'libstats_plugin.dylib',
'libvod_rtsp_plugin.dylib',
'libxml_plugin.dylib',
'misc/libvod_rtsp_plugin.dylib',
'misc/libxml_plugin.dylib',
#'libxtag_plugin.dylib',
'libi420_rgb_mmx_plugin.dylib',
'libi420_yuy2_mmx_plugin.dylib',
'libi422_yuy2_mmx_plugin.dylib',
'video_chroma/libi420_rgb_mmx_plugin.dylib',
'video_chroma/libi420_yuy2_mmx_plugin.dylib',
'video_chroma/libi422_yuy2_mmx_plugin.dylib',
#'libmemcpymmx_plugin.dylib',
#'libmemcpymmxext_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',
'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',
#'libvisual_plugin.dylib',
'libsecuretransport_plugin.dylib'
]
VLC_SEARCH_PATH=[
'/usr/local/opt/vlc/lib/vlc/plugins/',
'/usr/local/lib/vlc/plugins/',
]
QT_PLUGINS = [
@@ -200,39 +201,39 @@ QT_PLUGINS = [
]
SNORE_PLUGINS = [
'libsnore_backend_growl.so',
'libsnore_backend_osxnotificationcenter.so',
# 'libsnore_backend_growl.so',
# 'libsnore_backend_osxnotificationcenter.so',
]
TOMAHAWK_PLUGINS = [
'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,
'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',
]
QT_PLUGINS_SEARCH_PATH=[
'/usr/local/opt/qt5/plugins',
'/usr/local/Cellar/qt5/5.4.0/plugins',
]
SNORE_PLUGINS_SEARCH_PATH=[
'/usr/local/opt/snorenotify/lib/plugins/libsnore-qt5',
'/usr/local/Cellar/snorenotify/HEAD/lib/libsnore',
]
class Error(Exception):
@@ -246,8 +247,6 @@ class CouldNotFindQtPluginErrorFindFrameworkError(Error):
class InstallNameToolError(Error):
pass
class CouldNotFindFrameworkError(Error):
pass
class CouldNotFindQtPluginError(Error):
pass
@@ -309,7 +308,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) and not re.match(r'^\s*@loader_path/../lib', line):
elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
# Potentially already fixed library
if '.framework' in line:
relative_path = os.path.join(*line.split('/')[3:])
@@ -333,11 +332,6 @@ 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):
@@ -582,12 +576,12 @@ for plugin in TOMAHAWK_PLUGINS:
FixPlugin(plugin, '../MacOS')
for plugin in SNORE_PLUGINS:
FixPlugin(FindSnorePlugin(plugin), '../lib/plugins/libsnore-qt5')
FixPlugin(FindSnorePlugin(plugin), '../MacOS/libsnore')
try:
FixPlugin('%s_crash_reporter' % TARGET_NAME, '../MacOS')
FixPlugin('tomahawk_crash_reporter', '../MacOS')
except:
print 'Failed to find %s_crash_reporter' % TARGET_NAME
print 'Failed to find tomahawk_crash_reporter'
for plugin in QT_PLUGINS:
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))

View File

@@ -6,9 +6,9 @@ if ARGV.length < 2
exit
end
tarball = "#{ARGV[0].downcase}-#{ARGV[1]}.tar.bz2"
tarball = "tomahawk-#{ARGV[0]}.tar.bz2"
puts "Zipping: #{tarball}..."
`tar jcvf "#{tarball}" #{ARGV[0]}.app`
`tar jcvf "#{tarball}" Tomahawk.app`
puts "Signing..."
puts `openssl dgst -sha1 -binary < "#{tarball}" | openssl dgst -dss1 -sign "#{ARGV[2]}" | openssl enc -base64`
puts `openssl dgst -sha1 -binary < "#{tarball}" | openssl dgst -dss1 -sign "#{ARGV[1]}" | openssl enc -base64`

View File

@@ -1,55 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,55 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -102,7 +102,7 @@ Tomahawk.InfoSystem.InfoPlugin = {
notInCache: function (infoType, criteria) {
var requestMethod = 'request' + this.infoTypeString(infoType);
return RSVP.Promise.resolve(this[requestMethod](criteria));
return 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 RSVP.Promise.resolve(this[getInfoMethod](infoHash));
return Promise.resolve(this[getInfoMethod](infoHash));
}
};

View File

@@ -39,101 +39,7 @@ if ((typeof Tomahawk === "undefined") || (Tomahawk === null)) {
Tomahawk.apiVersion = "0.2.2";
//Statuses considered a success for HTTP request
var httpSuccessStatuses = [200, 201];
// install RSVP error handler for uncaught(!) errors
RSVP.on('error', function (reason) {
var resolverName = "";
if (Tomahawk.resolver.instance) {
resolverName = Tomahawk.resolver.instance.settings.name + " - ";
}
if (reason) {
console.error(resolverName + 'Uncaught error:', reason);
} else {
console.error(resolverName + 'Uncaught error: error thrown from RSVP but it was empty');
}
});
/**
* Compares versions strings
* (version1 < version2) == -1
* (version1 = version2) == 0
* (version1 > version2) == 1
*/
Tomahawk.versionCompare = function (version1, version2) {
var v1 = version1.split('.').map(function (item) {
return parseInt(item);
});
var v2 = version2.split('.').map(function (item) {
return parseInt(item);
});
var length = Math.max(v1.length, v2.length);
var i = 0;
for (; i < length; i++) {
if (typeof v1[i] == "undefined" || v1[i] === null) {
if (typeof v2[i] == "undefined" || v2[i] === null) {
// v1 == v2
return 0;
} else if (v2[i] === 0) {
continue;
} else {
// v1 < v2
return -1;
}
} else if (typeof v2[i] == "undefined" || v2[i] === null) {
if (v1[i] === 0) {
continue;
} else {
// v1 > v2
return 1;
}
} else if (v2[i] > v1[i]) {
// v1 < v2
return -1;
} else if (v2[i] < v1[i]) {
// v1 > v2
return 1;
}
}
// v1 == v2
return 0;
};
/**
* Check if this is at least specified tomahawk-api-version.
*/
Tomahawk.atLeastVersion = function (version) {
return (Tomahawk.versionCompare(Tomahawk.apiVersion, version) >= 0);
};
Tomahawk.resolver = {
scriptPath: Tomahawk.resolverData().scriptPath
};
Tomahawk.timestamp = function () {
return Math.round(new Date() / 1000);
};
Tomahawk.htmlDecode = (function () {
// this prevents any overhead from creating the object each time
var element = document.createElement('textarea');
function decodeHTMLEntities(str) {
if (str && typeof str === 'string') {
str = str.replace(/</g, "&lt;");
str = str.replace(/>/g, "&gt;");
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
}
return str;
}
return decodeHTMLEntities;
})();
Tomahawk.dumpResult = function (result) {
var results = result.results;
@@ -145,168 +51,6 @@ Tomahawk.dumpResult = function (result) {
Tomahawk.log("Done.");
};
// javascript part of Tomahawk-Object API
Tomahawk.extend = function (object, members) {
var F = function () {};
F.prototype = object;
var newObject = new F();
for (var key in members) {
newObject[key] = members[key];
}
return newObject;
};
//Deprecated for 0.9 resolvers. Reporting resolver capabilities is no longer necessary.
var TomahawkResolverCapability = {
NullCapability: 0,
Browsable: 1,
PlaylistSync: 2,
AccountFactory: 4,
UrlLookup: 8
};
//Deprecated for 0.9 resolvers. Use Tomahawk.UrlType instead.
var TomahawkUrlType = {
Any: 0,
Playlist: 1,
Track: 2,
Album: 4,
Artist: 8,
Xspf: 16
};
//Deprecated for 0.9 resolvers. Use Tomahawk.ConfigTestResultType instead.
var TomahawkConfigTestResultType = {
Other: 0,
Success: 1,
Logout: 2,
CommunicationError: 3,
InvalidCredentials: 4,
InvalidAccount: 5,
PlayingElsewhere: 6,
AccountExpired: 7
};
/**
* Resolver BaseObject, inherit it to implement your own resolver.
*/
var TomahawkResolver = {
init: function () {
},
scriptPath: function () {
return Tomahawk.resolverData().scriptPath;
},
getConfigUi: function () {
return {};
},
getUserConfig: function () {
return JSON.parse(window.localStorage[this.scriptPath()] || "{}");
},
saveUserConfig: function () {
var configJson = JSON.stringify(Tomahawk.resolverData().config);
window.localStorage[this.scriptPath()] = configJson;
this.newConfigSaved();
},
newConfigSaved: function () {
},
resolve: function (qid, artist, album, title) {
return {
qid: qid
};
},
search: function (qid, searchString) {
return this.resolve(qid, "", "", searchString);
},
artists: function (qid) {
return {
qid: qid
};
},
albums: function (qid, artist) {
return {
qid: qid
};
},
tracks: function (qid, artist, album) {
return {
qid: qid
};
},
collection: function () {
return {};
},
_adapter_testConfig: function (config) {
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
return {result: Tomahawk.ConfigTestResultType.Success};
});
},
testConfig: function () {
this.configTest();
},
getStreamUrl: function (qid, url) {
Tomahawk.reportStreamUrl(qid, url);
}
};
Tomahawk.Resolver = {
init: function () {
},
scriptPath: function () {
return Tomahawk.resolverData().scriptPath;
},
getConfigUi: function () {
return {};
},
getUserConfig: function () {
return JSON.parse(window.localStorage[this.scriptPath()] || "{}");
},
saveUserConfig: function () {
window.localStorage[this.scriptPath()] = JSON.stringify(Tomahawk.resolverData().config);
this.newConfigSaved(Tomahawk.resolverData().config);
},
newConfigSaved: function () {
},
testConfig: function () {
},
getStreamUrl: function (params) {
return params;
},
resolve: function() {
},
_adapter_resolve: function (params) {
return RSVP.Promise.resolve(this.resolve(params)).then(function (results) {
if(Array.isArray(results)) {
return {
'tracks': results
};
}
return results;
});
},
_adapter_search: function (params) {
return RSVP.Promise.resolve(this.search(params)).then(function (results) {
if(Array.isArray(results)) {
return {
'tracks': results
};
}
return results;
});
},
_adapter_testConfig: function (config) {
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
return {result: Tomahawk.ConfigTestResultType.Success};
});
}
};
// help functions
Tomahawk.valueForSubNode = function (node, tag) {
@@ -322,6 +66,7 @@ Tomahawk.valueForSubNode = function (node, tag) {
return element.textContent;
};
/**
* Internal counter used to identify retrievedMetadata call back from native
* code.
@@ -419,174 +164,6 @@ Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
/**
* 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)
* - username: The username for HTTP Basic Auth
* - password: The password for HTTP Basic Auth
* - errorHandler: callback called if the request was not completed
* - 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
*/
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];
};
return xhr;
});
} else {
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.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);
});
}
};
Tomahawk.ajax = function (url, settings) {
if (typeof url === "object") {
settings = url;
} else {
settings = settings || {};
settings.url = url;
}
settings.type = settings.type || settings.method || 'get';
settings.method = settings.type;
settings.dataFormat = settings.dataFormat || 'form';
if (settings.data) {
var formEncode = function (obj) {
var str = [];
for (var p in obj) {
if (obj[p] !== undefined) {
if (Array.isArray(obj[p])) {
for (var i = 0; i < obj[p].length; i++) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p][i]));
}
} else {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
}
str.sort();
return str.join("&");
};
if (typeof settings.data === 'object') {
if (settings.dataFormat == 'form') {
settings.data = formEncode(settings.data);
settings.contentType = settings.contentType || 'application/x-www-form-urlencoded';
} else if (settings.dataFormat == 'json') {
settings.data = JSON.stringify(settings.data);
settings.contentType = settings.contentType || 'application/json';
} else {
throw new Error("Tomahawk.ajax: unknown dataFormat requested: "
+ settings.dataFormat);
}
} else {
throw new Error("Tomahawk.ajax: data should be either object or string");
}
if (settings.type.toLowerCase() === 'get') {
settings.url += '?' + settings.data;
delete settings.data;
} else {
settings.headers = settings.headers || {};
if (!settings.headers.hasOwnProperty('Content-Type')) {
settings.headers['Content-Type'] = settings.contentType;
}
}
}
return doRequest(settings).then(function (xhr) {
if (settings.rawResponse) {
return xhr;
}
var responseText = xhr.responseText;
var contentType;
if (settings.dataType === 'json') {
contentType = 'application/json';
} else if (settings.dataType === 'xml') {
contentType = 'text/xml';
} else if (typeof xhr.getResponseHeader !== 'undefined') {
contentType = xhr.getResponseHeader('Content-Type');
} else if (xhr.hasOwnProperty('contentType')) {
contentType = xhr['contentType'];
} else {
contentType = 'text/html';
}
if (~contentType.indexOf('application/json')) {
return JSON.parse(responseText);
}
if (~contentType.indexOf('text/xml')) {
var domParser = new DOMParser();
return domParser.parseFromString(responseText, "text/xml");
}
return xhr.responseText;
});
};
Tomahawk.post = function (url, settings) {
if (typeof url === "object") {
settings = url;
} else {
settings = settings || {};
settings.url = url;
}
settings.method = 'POST';
return Tomahawk.ajax(settings);
};
Tomahawk.get = function (url, settings) {
return Tomahawk.ajax(url, settings);
};
Tomahawk.assert = function (assertion, message) {
Tomahawk.nativeAssert(assertion, message);
};
@@ -602,127 +179,6 @@ Tomahawk.hmac = function (key, message) {
return CryptoJS.HmacMD5(message, key).toString(CryptoJS.enc.Hex);
};
// Extracted from https://github.com/andrewrk/diacritics version 1.2.0
// Thanks to Andrew Kelley for this MIT-licensed diacritic removal code
// Initialisation / precomputation
(function() {
var replacementList = [
{base: ' ', chars: "\u00A0"},
{base: '0', chars: "\u07C0"},
{base: 'A', chars: "\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"},
{base: 'AA', chars: "\uA732"},
{base: 'AE', chars: "\u00C6\u01FC\u01E2"},
{base: 'AO', chars: "\uA734"},
{base: 'AU', chars: "\uA736"},
{base: 'AV', chars: "\uA738\uA73A"},
{base: 'AY', chars: "\uA73C"},
{base: 'B', chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"},
{base: 'C', chars: "\uFF43\u24b8\uff23\uA73E\u1E08"},
{base: 'D', chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"},
{base: 'Dh', chars: "\u00D0"},
{base: 'DZ', chars: "\u01F1\u01C4"},
{base: 'Dz', chars: "\u01F2\u01C5"},
{base: 'E', chars: "\u025B\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E\u1D07"},
{base: 'F', chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"},
{base: 'G', chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"},
{base: 'H', chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"},
{base: 'I', chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"},
{base: 'J', chars: "\u24BF\uFF2A\u0134\u0248\u0237"},
{base: 'K', chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"},
{base: 'L', chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"},
{base: 'LJ', chars: "\u01C7"},
{base: 'Lj', chars: "\u01C8"},
{base: 'M', chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"},
{base: 'N', chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"},
{base: 'NJ', chars: "\u01CA"},
{base: 'Nj', chars: "\u01CB"},
{base: 'O', chars: "\u24C4\uFF2F\xD2\xD3\xD4\u1ED2\u1ED0\u1ED6\u1ED4\xD5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\xD6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\xD8\u01FE\u0186\u019F\uA74A\uA74C"},
{base: 'OE', chars: "\u0152"},
{base: 'OI', chars: "\u01A2"},
{base: 'OO', chars: "\uA74E"},
{base: 'OU', chars: "\u0222"},
{base: 'P', chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"},
{base: 'Q', chars: "\u24C6\uFF31\uA756\uA758\u024A"},
{base: 'R', chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"},
{base: 'S', chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"},
{base: 'T', chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"},
{base: 'Th', chars: "\u00DE"},
{base: 'TZ', chars: "\uA728"},
{base: 'U', chars: "\u24CA\uFF35\xD9\xDA\xDB\u0168\u1E78\u016A\u1E7A\u016C\xDC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"},
{base: 'V', chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"},
{base: 'VY', chars: "\uA760"},
{base: 'W', chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"},
{base: 'X', chars: "\u24CD\uFF38\u1E8A\u1E8C"},
{base: 'Y', chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"},
{base: 'Z', chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"},
{base: 'a', chars: "\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250\u0251"},
{base: 'aa', chars: "\uA733"},
{base: 'ae', chars: "\u00E6\u01FD\u01E3"},
{base: 'ao', chars: "\uA735"},
{base: 'au', chars: "\uA737"},
{base: 'av', chars: "\uA739\uA73B"},
{base: 'ay', chars: "\uA73D"},
{base: 'b', chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"},
{base: 'c', chars: "\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184\u0043\u0106\u0108\u010A\u010C\u00C7\u0187\u023B"},
{base: 'd', chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"},
{base: 'dh', chars: "\u00F0"},
{base: 'dz', chars: "\u01F3\u01C6"},
{base: 'e', chars: "\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u01DD"},
{base: 'f', chars: "\u24D5\uFF46\u1E1F\u0192"},
{base: 'ff', chars: "\uFB00"},
{base: 'fi', chars: "\uFB01"},
{base: 'fl', chars: "\uFB02"},
{base: 'ffi', chars: "\uFB03"},
{base: 'ffl', chars: "\uFB04"},
{base: 'g', chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"},
{base: 'h', chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"},
{base: 'hv', chars: "\u0195"},
{base: 'i', chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"},
{base: 'j', chars: "\u24D9\uFF4A\u0135\u01F0\u0249"},
{base: 'k', chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"},
{base: 'l', chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"},
{base: 'lj', chars: "\u01C9"},
{base: 'm', chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"},
{base: 'n', chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"},
{base: 'nj', chars: "\u01CC"},
{base: 'o', chars: "\u24DE\uFF4F\xF2\xF3\xF4\u1ED3\u1ED1\u1ED7\u1ED5\xF5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\xF6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\xF8\u01FF\uA74B\uA74D\u0275\u0254\u1D11"},
{base: 'oe', chars: "\u0153"},
{base: 'oi', chars: "\u01A3"},
{base: 'oo', chars: "\uA74F"},
{base: 'ou', chars: "\u0223"},
{base: 'p', chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"},
{base: 'q', chars: "\u24E0\uFF51\u024B\uA757\uA759"},
{base: 'r', chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"},
{base: 's', chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"},
{base: 'ss', chars: "\xDF"},
{base: 't', chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"},
{base: 'th', chars: "\u00FE"},
{base: 'tz', chars: "\uA729"},
{base: 'u', chars: "\u24E4\uFF55\xF9\xFA\xFB\u0169\u1E79\u016B\u1E7B\u016D\xFC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"},
{base: 'v', chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"},
{base: 'vy', chars: "\uA761"},
{base: 'w', chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"},
{base: 'x', chars: "\u24E7\uFF58\u1E8B\u1E8D"},
{base: 'y', chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"},
{base: 'z', chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"}
];
Tomahawk.diacriticsMap = {};
var i, j, chars;
for (i = 0; i < replacementList.length; i += 1) {
chars = replacementList[i].chars;
for (j = 0; j < chars.length; j += 1) {
Tomahawk.diacriticsMap[chars[j]] = replacementList[i].base;
}
}
})();
Tomahawk.removeDiacritics = function (str) {
return str.replace(/[^\u0000-\u007E]/g, function (c) {
return Tomahawk.diacriticsMap[c] || c;
});
};
Tomahawk.localStorage = Tomahawk.localStorage || {
setItem: function (key, value) {
window.localStorage[key] = value;
@@ -745,115 +201,24 @@ Tomahawk.base64Encode = function (b) {
return window.btoa(b);
};
Tomahawk.PluginManager = {
wrapperPrefix: '_adapter_',
objects: {},
objectCounter: 0,
identifyObject: function (object) {
if (!object.hasOwnProperty('id')) {
object.id = this.objectCounter++;
}
return object.id;
},
registerPlugin: function (type, object) {
this.objects[this.identifyObject(object)] = object;
Tomahawk.log("registerPlugin: " + type + " id: " + object.id);
Tomahawk.registerScriptPlugin(type, object.id);
},
unregisterPlugin: function (type, object) {
this.objects[this.identifyObject(object)] = object;
Tomahawk.log("unregisterPlugin: " + type + " id: " + object.id);
Tomahawk.unregisterScriptPlugin(type, object.id);
},
resolve: [],
invokeSync: function (requestId, objectId, methodName, params) {
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);
} else {
if (!this.objects[objectId][methodName]) {
Tomahawk.log("Function not found: " + methodName);
}
}
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](params);
},
invoke: function (requestId, objectId, methodName, params) {
RSVP.Promise.resolve(this.invokeSync(requestId, objectId, methodName, params))
.then(function (result) {
Tomahawk.reportScriptJobResults({
requestId: requestId,
data: result
});
}, function (error) {
Tomahawk.reportScriptJobResults({
requestId: requestId,
error: error
});
});
}
};
var encodeParamsToNativeFunctions = function(param) {
return param;
};
Tomahawk.NativeScriptJobManager = {
idCounter: 0,
deferreds: {},
invoke: function (methodName, params) {
params = params || {};
var requestId = this.idCounter++;
var deferred = RSVP.defer();
this.deferreds[requestId] = deferred;
Tomahawk.invokeNativeScriptJob(requestId, methodName, encodeParamsToNativeFunctions(params));;
return deferred.promise;
Tomahawk.invokeNativeScriptJob(requestId, methodName, JSON.stringify(params));
this.deferreds[requestId] = RSVP.defer();
return this.deferreds[requestId].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];
}
};
Tomahawk.UrlType = {
Any: 0,
Playlist: 1,
Track: 2,
Album: 3,
Artist: 4,
XspfPlaylist: 5
};
<<<<<<< HEAD
Tomahawk.ConfigTestResultType = {
Other: 0,
@@ -1508,10 +873,6 @@ Tomahawk.Collection = {
});
},
revision: function (params) {
return RSVP.resolve();
},
_fuzzyIndexIdsToTracks: function (resultIds, id) {
if (typeof id === 'undefined') {
id = this.settings.id;
@@ -1563,14 +924,6 @@ 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);
@@ -1578,12 +931,7 @@ Tomahawk.Collection = {
search: function (params) {
var resultIds = Tomahawk.searchFuzzyIndex(params.query);
return this._fuzzyIndexIdsToTracks(resultIds).then(function(tracks) {
return {
tracks: tracks
};
});
return this._fuzzyIndexIdsToTracks(resultIds);
},
tracks: function (params, where) {
@@ -1627,7 +975,7 @@ Tomahawk.Collection = {
);
return t.execDeferredStatements();
}).then(function (results) {
return {tracks: results[0]};
return {results: resolverInstance._convertUrls(results[0])};
});
},
@@ -1801,13 +1149,73 @@ 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];
};
=======
>>>>>>> Move moar stuff over to es6 foo

View File

@@ -167,7 +167,5 @@
<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>

View File

@@ -69,13 +69,6 @@ Tomahawk::InfoSystem::XmppInfoPlugin::init()
}
const QString
Tomahawk::InfoSystem::XmppInfoPlugin::friendlyName() const
{
return "xmpp";
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData )
{

View File

@@ -38,8 +38,6 @@ namespace Tomahawk {
XmppInfoPlugin(XmppSipPlugin* parent);
virtual ~XmppInfoPlugin();
const QString friendlyName() const override;
signals:
void publishTune( QUrl url, Tomahawk::InfoSystem::InfoStringHash trackInfo );

View File

@@ -194,9 +194,9 @@ InfoSystem::InfoPluginPtr
XmppSipPlugin::infoPlugin()
{
if ( m_infoPlugin.isNull() )
m_infoPlugin = QSharedPointer< Tomahawk::InfoSystem::XmppInfoPlugin >( new Tomahawk::InfoSystem::XmppInfoPlugin( this ) );
m_infoPlugin = QPointer< Tomahawk::InfoSystem::XmppInfoPlugin >( new Tomahawk::InfoSystem::XmppInfoPlugin( this ) );
return m_infoPlugin;
return InfoSystem::InfoPluginPtr( m_infoPlugin.data() );
}
@@ -285,7 +285,7 @@ XmppSipPlugin::onConnect()
// load XmppInfoPlugin
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
{
infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
}
@@ -359,6 +359,7 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
if ( !m_infoPlugin.isNull() )
{
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() );
delete m_infoPlugin;
}
}

View File

@@ -128,7 +128,7 @@ private:
int m_currentPort;
QString m_currentResource;
QSharedPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_infoPlugin;
QPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_infoPlugin;
Tomahawk::Accounts::Account::ConnectionState m_state;
// sort out

View File

@@ -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><p>Can you tell us what you were doing when this happened?</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></body></html>");
reporter.setReportData( "BuildID", CRASHREPORTER_BUILD_ID );
reporter.setReportData( "ProductName", CRASHREPORTER_PRODUCT_NAME );

View File

@@ -3,15 +3,17 @@ include_directories(
${Boost_INCLUDE_DIR}
)
if(WIN32 OR APPLE)
if(BUILD_GUI AND LibsnoreQt5_FOUND)
if(BUILD_GUI AND LIBSNORE_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::Libsnore
SOURCES "${snore_srcs}" LINK_LIBRARIES "${SNORE_LINK_LIBRARIES}"
)
endif()
endif(BUILD_GUI AND LIBSNORE_FOUND)
endif(WIN32 OR APPLE)
list(APPEND simple_plugins

View File

@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013-2015, Hannah von Reth <vonreth@kde.org>
* Copyright 2013-2014, Patrick von Reth <vonreth@kde.org>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
*
@@ -27,15 +27,27 @@
#include "TomahawkVersion.h"
#include <libsnore/application.h>
#include <libsnore/notification/icon.h>
#include <snore/core/application.h>
#include <snore/core/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
{
@@ -49,13 +61,27 @@ SnoreNotifyPlugin::SnoreNotifyPlugin()
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoTrackUnresolved << InfoNowStopped << InfoInboxReceived;
Snore::SnoreCore &snore = Snore::SnoreCore::instance();
snore.loadPlugins( Snore::SnorePlugin::Backend | Snore::SnorePlugin::SecondaryBackend );
snore.setDefaultSettingsValue("Silent", true, Snore::LocalSetting );
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();
m_application = Snore::Application( qApp->applicationName(), m_defaultIcon );
m_application.hints().setValue( "use-markup", true );
m_application.hints().setValue( "windows-app-id", TOMAHAWK_APPLICATION_PACKAGE_NAME );
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" ) );
@@ -64,10 +90,9 @@ SnoreNotifyPlugin::SnoreNotifyPlugin()
addAlert( InfoNowStopped, tr( "Playback Stopped" ) );
addAlert( InfoInboxReceived, tr( "You received a Song recommendation" ) );
snore.registerApplication( m_application );
snore.setDefaultApplication( m_application );
m_snore->registerApplication( m_application );
connect( &snore, SIGNAL( actionInvoked( Snore::Notification ) ), this, SLOT( slotActionInvoked( Snore::Notification ) ) );
connect( m_snore, SIGNAL( actionInvoked( Snore::Notification ) ), this, SLOT( slotActionInvoked( Snore::Notification ) ) );
}
@@ -75,7 +100,8 @@ SnoreNotifyPlugin::~SnoreNotifyPlugin()
{
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
Snore::SnoreCore::instance().deregisterApplication( m_application );
m_snore->deregisterApplication( m_application );
m_snore->deleteLater();
}
void
@@ -85,19 +111,25 @@ 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." ), m_defaultIcon );
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." ) );
return;
case Tomahawk::InfoSystem::InfoNotifyUser:
notifyUser( Tomahawk::InfoSystem::InfoNotifyUser,pushData.infoPair.second.toString(), m_defaultIcon );
notifyUser( Tomahawk::InfoSystem::InfoNotifyUser,pushData.infoPair.second.toString() );
return;
case Tomahawk::InfoSystem::InfoNowStopped:
notifyUser( Tomahawk::InfoSystem::InfoNowStopped, tr( "%applicationName stopped playback." ), m_defaultIcon );
notifyUser( Tomahawk::InfoSystem::InfoNowStopped, tr( "%applicationName stopped playback." ) );
return;
case Tomahawk::InfoSystem::InfoNowPlaying:
@@ -125,10 +157,15 @@ 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 );
Snore::SnoreCore::instance().broadcastNotification( n );
m_snore->broadcastNotification( n );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "showing notification:" << messageText;
}
void
@@ -157,28 +194,41 @@ 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" ] ) );
// 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() );
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" ) ) );
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" ) ) );
// 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" ] ) );
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
messageText = QString( "<i></i>%1" ).arg( messageText );
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 );
}
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 = m_defaultIcon;
Snore::Icon image;
if ( map.contains( "cover" ) && map[ "cover" ].canConvert< QImage >() )
{
image = Snore::Icon( QPixmap::fromImage( map[ "cover" ].value< QImage >() ) );
image = Snore::Icon( map[ "cover" ].value< QImage >() );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << image;
}
notifyUser( InfoNowPlaying, messageText, image );
@@ -209,15 +259,26 @@ SnoreNotifyPlugin::inboxReceived( const QVariant& input )
return;
QString messageText;
// 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" ) ) );
// 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" ) ) );
// Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text
messageText = QString( "<i></i>%1" ).arg( messageText );
// 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" ] );
}
Snore::Icon icon( RESPATH "images/inbox-512x512.png" );
notifyUser( Tomahawk::InfoSystem::InfoInboxReceived, messageText, icon );

View File

@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013-2015, Hannah von Reth <vonreth@kde.org>
* Copyright 2013-2014, Patrick 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 <libsnore/snore.h>
#include <snore/core/snore.h>
namespace Tomahawk
{
@@ -63,8 +63,9 @@ protected slots:
void slotActionInvoked(Snore::Notification n);
private:
void notifyUser( InfoType type, const QString &messageText, Snore::Icon icon );
void notifyUser( InfoType type, const QString &messageText, Snore::Icon icon = Snore::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;

View File

@@ -34,7 +34,7 @@ public:
* Creates a Playdar HTTP interface
* @param ha Address to listen on
* @param port Port to listen on with HTTP
* @param sport Port to listen on with HTTPS
* @param sport Pot to listen on with HTTPS
* @param parent
*/
explicit PlaydarApi( QHostAddress ha, qint16 port, qint16 sport, QObject *parent = 0 );

View File

@@ -62,8 +62,6 @@ 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;
@@ -149,6 +147,7 @@ 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 );

View File

@@ -67,7 +67,7 @@ AtticaManager::AtticaManager( QObject* parent )
connect( &m_manager, SIGNAL( providerAdded( Attica::Provider ) ), this, SLOT( providerAdded( Attica::Provider ) ) );
// resolvers
// m_manager.addProviderFile( QUrl( "http://v09.bakery.tomahawk-player.org/resolvers/providers.xml" ) );
// m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) );
const QString url = QString( "%1/resolvers/providers.xml?version=%2" ).arg( hostname() ).arg( TomahawkUtils::appFriendlyVersion() );
QNetworkReply* reply = Tomahawk::Utils::nam()->get( QNetworkRequest( QUrl( url ) ) );

View File

@@ -37,7 +37,6 @@ set( libGuiSources
jobview/ErrorStatusMessage.cpp
jobview/IndexingJobItem.cpp
jobview/InboxJobItem.cpp
jobview/ScriptErrorStatusMessage.cpp
playlist/InboxModel.cpp
playlist/InboxView.cpp
@@ -200,6 +199,7 @@ list(APPEND libSources
MetaPlaylistInterface.cpp
Query.cpp
Result.cpp
ResultProvider.cpp
Source.cpp
Track.cpp
TrackData.cpp
@@ -501,7 +501,7 @@ set_target_properties(
AUTOMOC TRUE
VERSION ${TOMAHAWK_VERSION_SHORT}
SOVERSION ${TOMAHAWK_VERSION_SHORT}
OUTPUT_NAME ${TOMAHAWK_BASE_TARGET_NAME}
OUTPUT_NAME ${TOMAHAWK_TARGET_NAME}
)
@@ -524,6 +524,7 @@ ENDIF( UNIX AND NOT APPLE )
TARGET_LINK_LIBRARIES( ${TOMAHAWK_LIBRARY}
LINK_PRIVATE
${LIBVLC_LIBRARY}
${LIBVLCCORE_LIBRARY}
# Thirdparty shipped with tomahawk
${LIBPORTFWD_LIBRARIES}

View File

@@ -217,7 +217,7 @@ DownloadJob::download()
arguments[ "url" ] = m_format.url;
// HACK: *shrug* WIP.
Tomahawk::ScriptJob* job = collection->scriptObject()->invoke( "getStreamUrl", arguments );
Tomahawk::ScriptJob* job = collection->scriptObject()->invoke( "getStreamUrlPromise", arguments );
connect( job, SIGNAL( done(QVariantMap) ), SLOT( onUrlRetrieved(QVariantMap) ) );
job->start();
}

View File

@@ -175,7 +175,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypePlaylist ) )
if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) )
return true;
}
}
@@ -201,7 +201,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeTrack ) )
if ( resolver->canParseUrl( url, ExternalResolver::Track ) )
return true;
}
}
@@ -218,7 +218,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeAlbum ) )
if ( resolver->canParseUrl( url, ExternalResolver::Album ) )
return true;
}
}
@@ -235,7 +235,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeArtist ) )
if ( resolver->canParseUrl( url, ExternalResolver::Artist ) )
return true;
}
}
@@ -263,14 +263,9 @@ bool
DropJob::validateLocalFiles(const QString &paths, const QString &suffix)
{
QStringList filePaths = paths.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
QStringList::iterator it = filePaths.begin();
while ( it != filePaths.end() )
{
for ( QStringList::iterator it = filePaths.begin(); it != filePaths.end(); ++it )
if ( !validateLocalFile( *it, suffix ) )
it = filePaths.erase( it );
else
++it;
}
filePaths.erase( it );
return !filePaths.isEmpty();
}
@@ -311,7 +306,7 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data )
// Check Scriptresolvers
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypePlaylist ) )
if ( resolver->canParseUrl( url, ExternalResolver::Playlist ) )
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Accepting current drop as a playlist" << resolver->name();
return true;
@@ -768,7 +763,7 @@ DropJob::handleTrackUrls( const QString& urls )
{
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( track, ExternalResolver::UrlTypeAny ) )
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> ) ) );

View File

@@ -167,7 +167,7 @@ GlobalActionManager::openUrl( const QString& url )
QList< QPointer< ExternalResolver > > possibleResolvers;
foreach ( QPointer<ExternalResolver> resolver, Pipeline::instance()->scriptResolvers() )
{
if ( resolver->canParseUrl( url, ExternalResolver::UrlTypeAny ) )
if ( resolver->canParseUrl( url, ExternalResolver::Any ) )
{
canParse = true;
possibleResolvers << resolver;

View File

@@ -149,15 +149,6 @@ Pipeline::removeResolver( Resolver* r )
}
QList< Tomahawk::Resolver* >
Pipeline::resolvers() const
{
Q_D( const Pipeline );
return d->resolvers;
}
void
Pipeline::addResolver( Resolver* r )
{
@@ -332,13 +323,6 @@ 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 )
{
@@ -349,7 +333,7 @@ Pipeline::reportResults( QID qid, Tomahawk::Resolver* r, const QList< result_ptr
{
if ( !results.isEmpty() )
{
Resolver* resolvedBy = results[0]->resolvedBy();
ResultProvider* resolvedBy = results[0]->resolvedBy();
if ( resolvedBy )
{
tDebug() << "Result arrived too late for:" << qid << "by" << resolvedBy->name();
@@ -595,8 +579,8 @@ Pipeline::shunt( const query_ptr& q )
// we get here if we disable a resolver while a query is resolving
// OR we are just out of resolvers while query is still resolving
// since we seem to at least tried to kick off all of the resolvers,
// remove the '.keep' entry
//since we seem to at least tried to kick off all of the resolvers,
//remove the '.keep' entry
decQIDState( q, nullptr );
return;
}
@@ -636,7 +620,7 @@ Pipeline::checkQIDState( const Tomahawk::query_ptr& query )
Q_D( Pipeline );
QMutexLocker lock( &d->mut );
tDebug() << Q_FUNC_INFO << query->id() << d->qidsState.count( query->id() );
tDebug() << Q_FUNC_INFO << " " << query->id() << " " << d->qidsState.count( query->id() );
if ( d->qidsState.contains( query->id() ) )
{

View File

@@ -54,7 +54,6 @@ 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 );
@@ -66,7 +65,6 @@ public:
QList< QPointer< ExternalResolver > > scriptResolvers() const;
Tomahawk::ExternalResolver* resolverForPath( const QString& scriptPath );
QList< Resolver* > resolvers() const;
void addResolver( Resolver* r );
void removeResolver( Resolver* r );

View File

@@ -403,17 +403,12 @@ Query::resultSorter( const result_ptr& left, const result_ptr& right )
{
return false;
}
if ( left->isPreview() != right->isPreview() )
if ( !right->isPreview() )
{
return !left->isPreview();
return false;
}
if ( left->resolvedBy() != nullptr && right->resolvedBy() != nullptr )
{
return left->resolvedBy()->weight() > right->resolvedBy()->weight();
}
return left->id() > right->id();
return true;
}
if ( left->isPreview() != right->isPreview() )
@@ -641,11 +636,6 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
qTrackname = queryTrack()->trackSortname();
}
//Cleanup symbols for minor naming differences
qArtistname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
qTrackname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
qAlbumname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
// normal edit distance
const int artdist = TomahawkUtils::levenshtein( qArtistname, rArtistname );
const int trkdist = TomahawkUtils::levenshtein( qTrackname, rTrackname );

View File

@@ -491,7 +491,7 @@ Result::setFileId( unsigned int id )
}
Tomahawk::Resolver*
Tomahawk::ResultProvider*
Result::resolvedBy() const
{
if ( !m_collection.isNull() )
@@ -529,23 +529,12 @@ Result::track() const
}
QList< DownloadFormat >
Result::downloadFormats() const
{
QMutexLocker lock( &s_mutex );
return m_formats;
}
void
Result::setDownloadFormats( const QList<DownloadFormat>& formats )
{
if ( formats.isEmpty() )
return;
QMutexLocker lock( &s_mutex );
m_formats.clear();
foreach ( const DownloadFormat& format, formats )
{
@@ -573,7 +562,7 @@ Result::setDownloadFormats( const QList<DownloadFormat>& formats )
void
Result::onSettingsChanged()
{
if ( TomahawkSettings::instance()->downloadsPreferredFormat().toLower() != downloadFormats().first().extension.toLower() )
if ( TomahawkSettings::instance()->downloadsPreferredFormat().toLower() != m_formats.first().extension.toLower() )
{
setDownloadFormats( downloadFormats() );
emit updated();

View File

@@ -21,6 +21,7 @@
#ifndef RESULT_H
#define RESULT_H
#include "ResultProvider.h"
#include "DownloadJob.h"
#include "utils/TomahawkUtils.h"
#include "Typedefs.h"
@@ -85,9 +86,9 @@ public:
void setResolvedByResolver( Tomahawk::Resolver* resolver );
/**
* TODO: Make this a smart pointer
* This is very bad. ResultProvider is not a QObject and thus can not be tracked by a qt smart pointer ... :-(
*/
Resolver* resolvedBy() const;
ResultProvider* resolvedBy() const;
RID id() const;
bool isOnline() const;
@@ -131,7 +132,7 @@ public:
track_ptr track() const;
QList< DownloadFormat > downloadFormats() const;
QList<DownloadFormat> downloadFormats() const { return m_formats; }
void setDownloadFormats( const QList<DownloadFormat>& formats );
downloadjob_ptr downloadJob() const { return m_downloadJob; }

View File

@@ -1,10 +1,10 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
* Copyright (C) 2015 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
* 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,
@@ -15,23 +15,10 @@
* 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"
#include "ScriptErrorStatusMessage.h"
#include "../utils/Logger.h"
using namespace Tomahawk;
ScriptErrorStatusMessage::ScriptErrorStatusMessage( const QString& message, Tomahawk::ScriptAccount* account )
: ErrorStatusMessage( tr( "Script Error: %1" ).arg( message ) )
, m_account( account )
ResultProvider::~ResultProvider()
{
}
void
ScriptErrorStatusMessage::activated()
{
if ( m_account.isNull() )
return;
tDebug() << "ScriptErrorStatusMessage clicked: " << mainText() << m_account->name();
m_account->showDebugger();
}

View File

@@ -1,10 +1,10 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2016, Dominik Schmidt <domme@tomahawk-player.org>
* Copyright (C) 2015 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
* 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,
@@ -15,25 +15,28 @@
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCRIPTERRORSTATUSMESSAGE_H
#define SCRIPTERRORSTATUSMESSAGE_H
#include "ErrorStatusMessage.h"
#include "../resolvers/ScriptAccount.h"
#pragma once
#ifndef TOMAHAWK_RESULTPROVIDER_H
#define TOMAHAWK_RESULTPROVIDER_H
#include "DllMacro.h"
class DLLEXPORT ScriptErrorStatusMessage : public ErrorStatusMessage
class QPixmap;
class QString;
class QSize;
namespace Tomahawk
{
class DLLEXPORT ResultProvider
{
Q_OBJECT
public:
explicit ScriptErrorStatusMessage( const QString& scriptErrorMessage, Tomahawk::ScriptAccount* );
virtual ~ResultProvider();
void activated() override;
private:
QPointer< Tomahawk::ScriptAccount > m_account;
virtual QString name() const = 0;
virtual QPixmap icon( const QSize& size ) const = 0;
};
#endif // SCRIPTERRORSTATUSMESSAGE_H
}
#endif // TOMAHAWK_RESULTPROVIDER_H

View File

@@ -253,7 +253,7 @@ namespace Tomahawk
typedef QHash< QString, QString > InfoStringHash;
typedef QPair< QVariantMap, QVariant > PushInfoPair;
typedef QSharedPointer< InfoPlugin > InfoPluginPtr;
typedef QPointer< InfoPlugin > InfoPluginPtr;
}
namespace Network

View File

@@ -76,8 +76,6 @@ 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.

View File

@@ -517,15 +517,14 @@ ResolverAccount::removeBundle()
}
void
ResolverAccount::testConfig()
void ResolverAccount::testConfig()
{
// HACK: move to JSAccount once we have that properly
JSResolver* resolver = qobject_cast< Tomahawk::JSResolver* >( m_resolver );
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();
}
@@ -536,13 +535,6 @@ ResolverAccount::testConfig()
}
ExternalResolverGui*
ResolverAccount::resolver() const
{
return m_resolver;
}
void
ResolverAccount::onTestConfig( const QVariantMap& result )
{

View File

@@ -101,8 +101,6 @@ public:
void testConfig() override;
ExternalResolverGui* resolver() const;
private slots:
void resolverChanged();
void onTestConfig( const QVariantMap& result );

View File

@@ -71,7 +71,7 @@ LastFmAccount::LastFmAccount( const QString& accountId )
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
{
infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
}
}
@@ -82,6 +82,7 @@ LastFmAccount::~LastFmAccount()
if ( m_infoPlugin )
{
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() );
delete m_infoPlugin;
}
delete m_resolver.data();
@@ -167,11 +168,9 @@ InfoPluginPtr
LastFmAccount::infoPlugin()
{
if ( m_infoPlugin.isNull() )
{
m_infoPlugin = QSharedPointer< LastFmInfoPlugin>( new LastFmInfoPlugin( this ) );
}
m_infoPlugin = QPointer< LastFmInfoPlugin >( new LastFmInfoPlugin( this ) );
return m_infoPlugin;
return InfoPluginPtr( m_infoPlugin.data() );
}
bool

View File

@@ -105,7 +105,7 @@ private:
void hookupResolver();
QPointer<Tomahawk::ExternalResolverGui> m_resolver;
QSharedPointer<Tomahawk::InfoSystem::LastFmInfoPlugin> m_infoPlugin;
QPointer<Tomahawk::InfoSystem::LastFmInfoPlugin> m_infoPlugin;
QPointer<LastFmConfig> m_configWidget;
};

View File

@@ -65,6 +65,13 @@ 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)
@@ -79,17 +86,6 @@ 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() ) );
}

View File

@@ -116,12 +116,6 @@ SpotifyAccount::~SpotifyAccount()
{
clearUser();
if ( m_infoPlugin )
{
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() );
}
if ( m_spotifyResolver.isNull() )
return;
@@ -141,7 +135,7 @@ SpotifyAccount::init()
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
{
infoPlugin()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
}
@@ -372,10 +366,10 @@ SpotifyAccount::infoPlugin()
{
if ( m_infoPlugin.isNull() )
{
m_infoPlugin = QSharedPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) );
m_infoPlugin = QPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) );
}
return m_infoPlugin;
return InfoSystem::InfoPluginPtr( m_infoPlugin.data() );
}

View File

@@ -170,7 +170,7 @@ private:
QPointer<SpotifyAccountConfig> m_configWidget;
QPointer<QWidget> m_aboutWidget;
QPointer<ScriptResolver> m_spotifyResolver;
QSharedPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
QPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
QMap<QString, QVariant > m_qidToExtraData;

View File

@@ -277,7 +277,7 @@ SpotifyAccountConfig::showLoggedIn()
m_ui->verticalLayout->insertWidget( 1, m_loggedInUser, 0, Qt::AlignCenter );
}
qDebug() << "Showing logged in with username:" << m_verifiedUsername;
qDebug() << "Showing logged in withuserame:" << m_verifiedUsername;
m_loggedInUser->show();
m_loggedInUser->setText( tr( "Logged in as %1" ).arg( m_verifiedUsername ) );

View File

@@ -32,8 +32,6 @@
#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"
@@ -42,7 +40,6 @@
#include "SourceList.h"
#include "TomahawkSettings.h"
#include "UrlHandler.h"
#include "resolvers/ScriptJob.h"
#include <QDir>
@@ -577,64 +574,16 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
setCurrentTrack( result );
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 ) ) )
if ( !TomahawkUtils::isLocalResult( d->currentTrack->url() ) && !TomahawkUtils::isHttpResult( d->currentTrack->url() )
&& !TomahawkUtils::isRtmpResult( d->currentTrack->url() ) )
{
// Not an http(s) or RTMP URL, get IO device
QSharedPointer< QIODevice > sp;
performLoadIODevice( result, streamUrl );
performLoadIODevice( d->currentTrack, d->currentTrack->url() );
}
else
{
// 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 );
QSharedPointer< QIODevice > io;
performLoadTrack( result, result->url(), io );
}
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 );
}
@@ -669,7 +618,7 @@ AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url )
void
AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io )
AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString url, QSharedPointer< QIODevice > io )
{
if ( QThread::currentThread() != thread() )
{

View File

@@ -28,7 +28,6 @@
#include "DllMacro.h"
class NetworkReply;
class AudioEnginePrivate;
class DLLEXPORT AudioEngine : public QObject
@@ -181,12 +180,8 @@ 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 performLoadTrack( const Tomahawk::result_ptr result, const QString url, QSharedPointer< QIODevice > io ); //only call from loadTrack or performLoadIODevice kthxbi
void loadPreviousTrack();
void loadNextTrack();

View File

@@ -35,7 +35,7 @@ using namespace Tomahawk;
Collection::Collection( const source_ptr& source, const QString& name, QObject* parent )
: Resolver( parent )
: QObject( parent )
, m_name( name )
, m_lastmodified( 0 )
, m_changed( false )

View File

@@ -33,7 +33,7 @@
#include "collection/ArtistsRequest.h"
#include "collection/AlbumsRequest.h"
#include "collection/TracksRequest.h"
#include "../resolvers/Resolver.h"
#include "../ResultProvider.h"
#include "DllMacro.h"
@@ -46,7 +46,7 @@
namespace Tomahawk
{
class DLLEXPORT Collection : public Resolver
class DLLEXPORT Collection : public QObject, public ResultProvider
{
Q_OBJECT

View File

@@ -251,32 +251,3 @@ 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);
}

View File

@@ -65,11 +65,6 @@ 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 );

View File

@@ -277,8 +277,8 @@ InfoSystem::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() )
{
tLog() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread(): " << plugin->friendlyName();
Q_ASSERT( false );
tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()";
return;
}

View File

@@ -58,7 +58,13 @@ InfoSystemWorker::InfoSystemWorker()
InfoSystemWorker::~InfoSystemWorker()
{
tDebug() << Q_FUNC_INFO;
tDebug() << Q_FUNC_INFO << " beginning";
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
if( plugin )
delete plugin.data();
}
tDebug() << Q_FUNC_INFO << " finished";
}
@@ -130,6 +136,29 @@ InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
emit updatedSupportedGetTypes( QSet< InfoType >::fromList( m_infoGetMap.keys() ) );
emit updatedSupportedPushTypes( QSet< InfoType >::fromList( m_infoPushMap.keys() ) );
connect( plugin.data(), SIGNAL( destroyed( QObject* ) ), SLOT( onInfoPluginDeleted() ) );
}
void
InfoSystemWorker::onInfoPluginDeleted()
{
foreach( const InfoPluginPtr& plugin, m_plugins )
{
if ( plugin.isNull() )
{
m_plugins.removeOne( plugin );
foreach( InfoType type, m_infoGetMap.keys() )
{
m_infoGetMap[type].removeOne( plugin );
}
foreach( InfoType type, m_infoPushMap.keys() )
{
m_infoPushMap[type].removeOne( plugin );
}
}
}
}

View File

@@ -72,6 +72,7 @@ public slots:
private slots:
void checkTimeoutsTimerFired();
void onInfoPluginDeleted();
private:
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes );

View File

@@ -33,12 +33,6 @@ JobStatusItem::~JobStatusItem()
}
void
JobStatusItem::activated()
{
}
bool
JobStatusItem::allowMultiLine() const
{

View File

@@ -53,8 +53,6 @@ public:
virtual QString mainText() const = 0;
virtual QString rightColumnText() const { return QString(); };
virtual void activated();
/**
* If collapse item is true, sending multiple items of the same type will "collapse" them into one
* instead of showing each individually. In this case, the right column from the item will be ignored

View File

@@ -118,7 +118,6 @@ JobStatusView::setModel( JobStatusSortModel* m )
connect( m_view->model(), SIGNAL( customDelegateJobInserted( int, JobStatusItem* ) ), this, SLOT( customDelegateJobInserted( int, JobStatusItem* ) ) );
connect( m_view->model(), SIGNAL( customDelegateJobRemoved( int ) ), this, SLOT( customDelegateJobRemoved( int ) ) );
connect( m_view->model(), SIGNAL( refreshDelegates() ), this, SLOT( refreshDelegates() ) );
connect( m_view, SIGNAL( activated( QModelIndex ) ), this, SLOT( onItemActivated( QModelIndex ) ) );
foreach ( const QPointer<JobStatusItem> item, s_jobItems )
{
@@ -185,21 +184,6 @@ JobStatusView::refreshDelegates()
}
void
JobStatusView::onItemActivated( const QModelIndex& index )
{
QVariant itemVar = index.data( JobStatusModel::JobDataRole );
if ( !itemVar.canConvert< JobStatusItem* >() || !itemVar.value< JobStatusItem* >() )
{
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem*";
return;
}
JobStatusItem* item = itemVar.value< JobStatusItem* >();
item->activated();
}
void
JobStatusView::checkCount()
{

View File

@@ -59,7 +59,6 @@ private slots:
void customDelegateJobInserted( int row, JobStatusItem* item );
void customDelegateJobRemoved( int row );
void refreshDelegates();
void onItemActivated( const QModelIndex& index );
private:
QListView* m_view;

View File

@@ -119,9 +119,8 @@ int
PlayableModel::columnCount( const QModelIndex& parent ) const
{
Q_UNUSED( parent );
Q_D( const PlayableModel );
return d->header.length();
return 13;
}
@@ -445,21 +444,14 @@ PlayableModel::flags( const QModelIndex& index ) const
if ( index.isValid() )
{
Qt::ItemFlags returnFlags = defaultFlags;
if ( index.column() == 0 )
{
returnFlags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
}
else if ( index.column() == PlayableModel::Download )
{
returnFlags |= Qt::ItemIsEditable | defaultFlags;
return Qt::ItemIsEditable | defaultFlags;
}
if ( areAllColumnsEditable() ) {
returnFlags |= Qt::ItemIsEditable;
}
return returnFlags;
}
return Qt::ItemIsDropEnabled | defaultFlags;
@@ -1179,22 +1171,6 @@ PlayableModel::setIcon( const QPixmap& pixmap )
}
void
PlayableModel::setAllColumnsEditable( bool editable )
{
Q_D( PlayableModel );
d->areAllColumnsEditable = editable;
}
bool
PlayableModel::areAllColumnsEditable() const
{
Q_D( const PlayableModel );
return d->areAllColumnsEditable;
}
int
PlayableModel::trackCount() const
{

View File

@@ -96,11 +96,6 @@ public:
virtual QPixmap icon() const;
virtual void setIcon( const QPixmap& pixmap );
// HACK: we need to set column 0 editable for DropDownButton in TrackView
void setAllColumnsEditable( bool editable );
bool areAllColumnsEditable() const;
virtual int trackCount() const;
virtual int itemCount() const;

View File

@@ -38,7 +38,6 @@ public:
, rootItem( new PlayableItem( 0 ) )
, readOnly( true )
, loading( _loading )
, areAllColumnsEditable( false )
{
}
@@ -59,7 +58,6 @@ private:
QStringList header;
bool loading;
bool areAllColumnsEditable;
};
#endif // PLAYABLEMODEL_P_H

View File

@@ -607,7 +607,25 @@ PlayableProxyModel::columnCount( const QModelIndex& parent ) const
{
Q_UNUSED( parent );
return m_headerStyle[ m_style ].length();
switch ( m_style )
{
case SingleColumn:
return 1;
break;
case Collection:
return 10;
break;
case Locker:
return 11;
break;
case Detailed:
default:
return 12;
break;
}
}
@@ -715,13 +733,6 @@ PlayableProxyModel::setFilter( const QString& pattern )
}
int
PlayableProxyModel::mapSourceColumnToColumn( PlayableModel::Columns column )
{
return m_headerStyle[ m_style ].indexOf( column );
}
void
PlayableProxyModel::setCurrentIndex( const QModelIndex& index )
{

View File

@@ -98,8 +98,6 @@ public:
virtual void setFilter( const QString& pattern );
virtual void updateDetailedInfo( const QModelIndex& index );
int mapSourceColumnToColumn( PlayableModel::Columns column );
signals:
void filterChanged( const QString& filter );

View File

@@ -885,9 +885,7 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
}
else if ( m_view->proxyModel()->style() == PlayableProxyModel::Locker && index.column() == PlayableModel::Download )
{
m_model->sourceModel()->setAllColumnsEditable( true );
m_view->edit( index );
m_model->sourceModel()->setAllColumnsEditable( false );
return true;
}

View File

@@ -262,15 +262,8 @@ 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 (%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->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->setFixedWidth( width() - 32 - 4 );
NewClosure( resolverLabel, SIGNAL( clicked() ), const_cast< AudioEngine* >( AudioEngine::instance() ),

View File

@@ -45,9 +45,6 @@
#include <QScrollBar>
#include <QDrag>
// HACK
#include <QTableView>
#define SCROLL_TIMEOUT 280
using namespace Tomahawk;
@@ -86,13 +83,6 @@ TrackView::TrackView( QWidget* parent )
setEditTriggers( NoEditTriggers );
setHeader( m_header );
// HACK: enable moving of first column: QTBUG-33974 / https://github.com/qtproject/qtbase/commit/e0fc088c0c8bc61dbcaf5928b24986cd61a22777
QTableView unused;
unused.setVerticalHeader( header() );
header()->setParent( this );
unused.setVerticalHeader( new QHeaderView( Qt::Horizontal, &unused ) );
setSortingEnabled( true );
sortByColumn( -1 );
setContextMenuPolicy( Qt::CustomContextMenu );

View File

@@ -68,12 +68,11 @@ public:
enum UrlType
{
UrlTypeAny = 0x00,
UrlTypePlaylist = 0x01,
UrlTypeTrack = 0x02,
UrlTypeAlbum = 0x04,
UrlTypeArtist = 0x08,
UrlTypeXspf = 0x10
Any = 0x00,
Playlist = 0x01,
Track = 0x02,
Album = 0x04,
Artist = 0x08
};
Q_DECLARE_FLAGS( UrlTypes, UrlType )
Q_FLAGS( UrlTypes )

View File

@@ -30,8 +30,6 @@
#include <QWidget>
#include <QUiLoader>
#include <QBoxLayout>
#include <QPushButton>
#include <QDesktopServices>
Tomahawk::ExternalResolverGui::ExternalResolverGui(const QString& filePath)
: Tomahawk::ExternalResolver(filePath)
@@ -84,30 +82,6 @@ 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 )
{
@@ -120,8 +94,6 @@ 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 );

View File

@@ -50,8 +50,7 @@ protected:
QByteArray fixDataImagePaths( const QByteArray& data, bool compressed, const QVariantMap& images );
private:
void addChildProperties( QObject* widget, QVariantMap& m );
void setupClickHandlerOnUrlButtons( QObject* widget );
void addChildProperties( QObject* parent, QVariantMap& m );
};
}; //ns

View File

@@ -67,14 +67,6 @@ JSAccount::scriptPluginFactory( const QString& type, const scriptobject_ptr& obj
}
void
JSAccount::showDebugger()
{
tLog() << Q_FUNC_INFO << name() << "Show debugger";
m_engine->showWebInspector();
}
QString
JSAccount::serializeQVariantMap( const QVariantMap& map )
{
@@ -178,41 +170,6 @@ 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 )

View File

@@ -69,20 +69,15 @@ public:
void setResolver( JSResolver* resolver );
void scriptPluginFactory( const QString& type, const scriptobject_ptr& object ) override;
void showDebugger() override;
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 );
ScriptEngine* m_engine;
std::unique_ptr<ScriptEngine> m_engine;
// HACK: the order of initializen is flawed, tbr
JSResolver* m_resolver;
};

View File

@@ -44,13 +44,6 @@
#include "Track.h"
#include "ScriptInfoPlugin.h"
#include "JSAccount.h"
#include "ScriptJob.h"
// lookupUrl stuff
#include "playlist/PlaylistTemplate.h"
#include "playlist/XspfPlaylistTemplate.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include <QDir>
#include <QFile>
@@ -216,52 +209,21 @@ JSResolver::init()
}
const QByteArray scriptContents = scriptFile.readAll();
// tomahawk.js
{
// add c++ part of tomahawk javascript library
d->scriptAccount->addToJavaScriptWindowObject( "Tomahawk", d->resolverHelper );
// load es6-promises shim
d->scriptAccount->loadScript( RESPATH "js/rsvp-latest.min.js" );
// Load CrytoJS core
d->scriptAccount->loadScript( RESPATH "js/cryptojs-core.js" );
// Load CryptoJS modules
QStringList jsfiles;
jsfiles << "*.js";
QDir cryptojs( RESPATH "js/cryptojs" );
foreach ( QString jsfile, cryptojs.entryList( jsfiles ) )
{
d->scriptAccount->loadScript( RESPATH "js/cryptojs/" + jsfile );
}
// Load tomahawk.js
d->scriptAccount->loadScript( RESPATH "js/tomahawk.js" );
}
// tomahawk-infosystem.js
{
// TODO: be smarter about this, only include this if the resolver supports infoplugins
// add deps
d->scriptAccount->loadScript( RESPATH "js/tomahawk-infosystem.js" );
}
// add resolver dependencies, if any
d->scriptAccount->loadScripts( d->requiredScriptPaths );
d->scriptAccount->addToJavaScriptWindowObject( "Tomahawk", d->resolverHelper );
// add resolver
d->scriptAccount->loadScript( filePath() );
// HACK: register resolver object
d->scriptAccount->evaluateJavaScript( "Tomahawk.PluginManager.registerPlugin('resolver', Tomahawk.resolver.instance);" );
// init resolver
scriptObject()->syncInvoke( "init" );
d->scriptAccount->evaluateJavaScript(
"var resolverInstance = new (require('main').default);"
"Tomahawk.PluginManager.registerPlugin('resolver', resolverInstance);"
);
QVariantMap m = scriptObject()->syncInvoke( "settings" ).toMap();
// init resolver
resolverInit();
QVariantMap m = resolverSettings();
d->name = m.value( "name" ).toString();
d->weight = m.value( "weight", 0 ).toUInt();
d->timeout = m.value( "timeout", 25 ).toUInt() * 1000;
@@ -311,8 +273,6 @@ JSResolver::start()
Q_D( JSResolver );
d->stopped = false;
d->resolverHelper->start();
if ( d->ready )
Tomahawk::Pipeline::instance()->addResolver( this );
else
@@ -327,13 +287,20 @@ 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 ) )
{
QVariantMap arguments;
arguments["url"] = url;
arguments["type"] = (int) type;
return scriptObject()->syncInvoke( "canParseUrl", arguments ).toBool();
QString eval = QString( "canParseUrl( '%1', %2 )" )
.arg( JSAccount::escape( QString( url ) ) )
.arg( (int) type );
return callOnResolver( eval ).toBool();
}
else
{
@@ -346,8 +313,14 @@ JSResolver::canParseUrl( const QString& url, UrlType type )
void
JSResolver::lookupUrl( const QString& url )
{
Q_D( const JSResolver );
if ( QThread::currentThread() != thread() )
{
QMetaObject::invokeMethod( this, "lookupUrl", Qt::QueuedConnection,
Q_ARG( QString, url ) );
return;
}
Q_D( const JSResolver );
if ( !d->capabilities.testFlag( UrlLookup ) )
{
@@ -355,176 +328,19 @@ JSResolver::lookupUrl( const QString& url )
return;
}
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();
}
QString eval = QString( "lookupUrl( '%1' )" )
.arg( JSAccount::escape( QString( url ) ) );
void
JSResolver::onLookupUrlRequestDone( const QVariantMap& result )
{
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.
m_pendingUrl = QString();
m_pendingAlbum = album_ptr();
UrlTypes type = (UrlTypes) result.value( "type" ).toInt();
if ( type == UrlTypeArtist )
QVariantMap m = callOnResolver( eval ).toMap();
if ( m.isEmpty() )
{
QString name = result.value( "name" ).toString();
Q_ASSERT( !name.isEmpty() );
emit informationFound( url, Artist::get( name, true ).objectCast<QObject>() );
}
else if ( type == UrlTypeAlbum )
{
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 informationFound( url, album.objectCast<QObject>() );
}
}
else if ( type == 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 << name() << "Got empty track information for " << url;
emit informationFound( url, QSharedPointer<QObject>() );
}
else
{
emit informationFound( url, query.objectCast<QObject>() );
}
}
else if ( type == 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 << 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 == 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 << name() << "Got playlist for " << url;
pltemplate->load();
}
else
{
tLog( LOGVERBOSE ) << Q_FUNC_INFO << name() << "No usable information found for " << url;
emit informationFound( url, QSharedPointer<QObject>() );
}
}
query_ptr
JSResolver::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;
}
void
JSResolver::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 the resolver doesn't return anything, async api is used
return;
}
emit informationFound( m_pendingUrl, m_pendingAlbum.objectCast<QObject>() );
m_pendingAlbum = album_ptr();
m_pendingUrl = QString();
}
void
JSResolver::pltemplateTracksLoadedForUrl( const QString& url, const playlisttemplate_ptr& pltemplate )
{
tLog() << Q_FUNC_INFO;
emit informationFound( url, pltemplate.objectCast<QObject>() );
QString errorMessage = tr( "Script Resolver Warning: API call %1 returned data synchronously." ).arg( eval );
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorMessage ) );
tDebug() << errorMessage << m;
}
@@ -540,59 +356,38 @@ JSResolver::error() const
void
JSResolver::resolve( const Tomahawk::query_ptr& query )
{
ScriptJob* job = scriptAccount()->resolve( scriptObject(), query, "resolver" );
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() )
if ( QThread::currentThread() != thread() )
{
Tomahawk::Pipeline::instance()->reportError( qid, this );
QMetaObject::invokeMethod( this, "resolve", Qt::QueuedConnection, Q_ARG(Tomahawk::query_ptr, query) );
return;
}
QString eval;
if ( !query->isFullTextQuery() )
{
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() ) );
}
else
{
if ( !data.value( "artists" ).isNull() )
{
QList< artist_ptr > artists = scriptAccount()->parseArtistVariantList( data.value( "artists" ).toList() );
Tomahawk::Pipeline::instance()->reportArtists( qid, artists );
}
if ( !data.value( "albums" ).isNull() )
{
QList< album_ptr > albums = scriptAccount()->parseAlbumVariantList( data.value( "albums" ).toList() );
Tomahawk::Pipeline::instance()->reportAlbums( qid, albums );
}
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 );
eval = QString( "search( '%1', '%2' )" )
.arg( JSAccount::escape( query->id() ) )
.arg( JSAccount::escape( query->fullTextQuery() ) );
}
sender()->deleteLater();
QVariantMap m = callOnResolver( eval ).toMap();
}
void
JSResolver::stop()
{
Q_D( JSResolver );
d->stopped = true;
d->resolverHelper->stop();
scriptAccount()->stop();
@@ -606,7 +401,7 @@ JSResolver::loadUi()
{
Q_D( JSResolver );
QVariantMap m = scriptObject()->syncInvoke( "getConfigUi" ).toMap();
QVariantMap m = callOnResolver( "getConfigUi()" ).toMap();
bool compressed = m.value( "compressed", "false" ).toBool();
qDebug() << "Resolver has a preferences widget! compressed?" << compressed;
@@ -658,7 +453,7 @@ JSResolver::saveConfig()
// qDebug() << Q_FUNC_INFO << saveData;
d->resolverHelper->setResolverConfig( saveData.toMap() );
scriptObject()->syncInvoke( "saveUserConfig" );
callOnResolver( "saveUserConfig()" );
}
@@ -689,25 +484,39 @@ JSResolver::onCapabilitiesChanged( Tomahawk::ExternalResolver::Capabilities capa
}
QVariantMap
JSResolver::resolverSettings()
{
return callOnResolver( "settings" ).toMap();
}
QVariantMap
JSResolver::resolverUserConfig()
{
return scriptObject()->syncInvoke( "getUserConfig" ).toMap();
return callOnResolver( "getUserConfig()" ).toMap();
}
QString
JSResolver::instanceUUID()
QVariantMap
JSResolver::resolverInit()
{
return Tomahawk::Database::instance()->impl()->dbid();
return callOnResolver( "init()" ).toMap();
}
ScriptJob*
JSResolver::getStreamUrl( const result_ptr& result )
QVariant
JSResolver::callOnResolver( const QString& scriptSource )
{
QVariantMap arguments;
arguments["url"] = result->url();
Q_D( JSResolver );
return scriptObject()->invoke( "getStreamUrl", arguments );
QString propertyName = scriptSource.split('(').first();
return d->scriptAccount->evaluateJavaScriptWithResult( QString(
"if(resolverInstance['_adapter_%1']) {"
" resolverInstance._adapter_%2;"
"} else {"
" resolverInstance.%2;"
"}"
).arg( propertyName ).arg( scriptSource ) );
}

View File

@@ -75,8 +75,6 @@ public:
ScriptAccount* scriptAccount() const;
ScriptJob* getStreamUrl( const result_ptr& result ) override;
public slots:
void resolve( const Tomahawk::query_ptr& query ) override;
void stop() override;
@@ -91,10 +89,6 @@ signals:
protected:
QVariant callOnResolver( const QString& scriptSource );
private slots:
void onResolveRequestDone(const QVariantMap& data);
void onLookupUrlRequestDone(const QVariantMap& data);
private:
void init();
@@ -102,20 +96,12 @@ private:
void onCapabilitiesChanged( Capabilities capabilities );
// encapsulate javascript calls
QVariantMap resolverSettings();
QVariantMap resolverUserConfig();
QVariantMap resolverInit();
Q_DECLARE_PRIVATE( JSResolver )
QScopedPointer<JSResolverPrivate> d_ptr;
// TODO: move lookupUrl stuff to its own plugin type
QString instanceUUID();
static Tomahawk::query_ptr parseTrack( const QVariantMap& track );
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 );
void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate );
};
} // ns: Tomahawk

View File

@@ -21,6 +21,10 @@
#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"
@@ -47,8 +51,6 @@
#include <QMap>
#include <QWebFrame>
#include <QLocale>
#include <QNetworkReply>
#include <taglib/asffile.h>
#include <taglib/flacfile.h>
#include <taglib/id3v2framefactory.h>
@@ -74,25 +76,11 @@ JSResolverHelper::JSResolverHelper( const QString& scriptPath, JSResolver* paren
: QObject( parent )
, m_resolver( parent )
, m_scriptPath( scriptPath )
, m_stopped( false )
, m_urlCallbackIsAsync( false )
{
}
void
JSResolverHelper::start()
{
m_stopped = false;
}
void
JSResolverHelper::stop()
{
m_stopped = true;
}
QByteArray
JSResolverHelper::readRaw( const QString& fileName )
{
@@ -152,6 +140,55 @@ 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
{
@@ -446,13 +483,123 @@ 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;
@@ -468,9 +615,6 @@ JSResolverHelper::nativeReportCapabilities( const QVariant& v )
void
JSResolverHelper::reportScriptJobResults( const QVariantMap& result )
{
if( m_stopped )
return;
m_resolver->d_func()->scriptAccount->reportScriptJobResult( result );
}
@@ -478,9 +622,6 @@ 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 );
}
@@ -488,10 +629,28 @@ JSResolverHelper::registerScriptPlugin( const QString& type, const QString& obje
void
JSResolverHelper::unregisterScriptPlugin( const QString& type, const QString& objectId )
{
if( m_stopped )
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() )
return;
m_resolver->d_func()->scriptAccount->unregisterScriptPlugin( type, objectId );
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>() );
}
@@ -509,6 +668,31 @@ 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 )
@@ -519,6 +703,61 @@ 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(resolverInstance['_adapter_%1']) {"
" resolverInstance._adapter_%1( {qid: '%2', url: '%3'} );"
"} else {"
" resolverInstance.%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( "resolverInstance.%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,
@@ -657,27 +896,12 @@ 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 QVariantMap& options )
JSResolverHelper::nativeAsyncRequest( const int requestId, const QString& url,
const QVariantMap& headers,
const QVariantMap& options )
{
QString url = options[ "url" ].toString();
QVariantMap headers = options[ "headers" ].toMap();
QNetworkRequest req( url );
foreach ( const QString& key, headers.keys() )
{
@@ -733,16 +957,17 @@ 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 );
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 );
QString javascript = QString( "Tomahawk.nativeAsyncRequestDone( %1, %2 );" )
.arg( QString::number( requestId ) )
.arg( json );
m_resolver->d_func()->scriptAccount->evaluateJavaScript( javascript );
}
@@ -918,3 +1143,43 @@ 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 );
}

View File

@@ -54,9 +54,6 @@ public:
*/
void setResolverConfig( const QVariantMap& config );
void start();
void stop();
/**
* Get the instance unique account id for this resolver.
*
@@ -64,6 +61,9 @@ 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,9 +89,20 @@ public:
int sizehint,
const QVariantMap& options );
Q_INVOKABLE void invokeNativeScriptJob( int requestId,
const QString& methodName,
const QVariantMap& params );
/**
* 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 );
/**
* Lucene++ indices for JS resolvers
@@ -111,10 +122,18 @@ 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 );
@@ -123,6 +142,10 @@ 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 );
@@ -131,20 +154,27 @@ 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;
bool m_stopped;
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;
};
} // ns: Tomahawk

View File

@@ -17,31 +17,10 @@
*/
#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 );
}

View File

@@ -19,6 +19,7 @@
#ifndef RESOLVER_H
#define RESOLVER_H
#include "../ResultProvider.h"
#include "Typedefs.h"
#include "DllMacro.h"
@@ -35,23 +36,21 @@
namespace Tomahawk
{
class ScriptJob;
class DLLEXPORT Resolver : public QObject
class DLLEXPORT Resolver : public QObject, public ResultProvider
{
Q_OBJECT
public:
Resolver( QObject* parent = nullptr );
virtual QString name() const = 0;
virtual QPixmap icon( const QSize& size ) const;
Resolver() {}
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

View File

@@ -32,8 +32,6 @@
#include "ScriptInfoPlugin.h"
// TODO:
#include "../Artist.h"
#include "../Album.h"
#include "../Result.h"
#include "../Track.h"
#include <QTime>
@@ -203,10 +201,6 @@ ScriptAccount::unregisterScriptPlugin( const QString& type, const QString& objec
{
m_infoPluginFactory->unregisterPlugin( object );
}
else if( type == "linkParser" )
{
// TODO
}
else
{
tLog() << "This plugin type is not handled by Tomahawk or simply cannot be removed yet";
@@ -237,10 +231,6 @@ ScriptAccount::scriptPluginFactory( const QString& type, const scriptobject_ptr&
ScriptLinkGeneratorPlugin* lgp = new ScriptLinkGeneratorPlugin( object );
Utils::LinkGenerator::instance()->addPlugin( lgp );
}
else if( type == "linkParser" )
{
tLog() << "Plugin registered linkParser, which is not implemented yet. UrlLookup won't work";
}
else if ( type == "infoPlugin" )
{
m_infoPluginFactory->registerPlugin( object, this );
@@ -257,12 +247,6 @@ ScriptAccount::scriptPluginFactory( const QString& type, const scriptobject_ptr&
}
void
ScriptAccount::showDebugger()
{
}
void
ScriptAccount::onJobDeleted( const QString& jobId )
{
@@ -270,67 +254,15 @@ ScriptAccount::onJobDeleted( const QString& jobId )
}
QList< Tomahawk::artist_ptr >
ScriptAccount::parseArtistVariantList( const QVariantList& artistList )
{
QList< Tomahawk::artist_ptr > artists;
QString artist;
foreach( const QVariant& a, artistList )
{
artist = a.toString().trimmed();
if ( artist.isEmpty() )
continue;
artists << Tomahawk::Artist::get( artist );
}
return artists;
}
QList< Tomahawk::album_ptr >
ScriptAccount::parseAlbumVariantList( const QVariantList& albumList )
{
QList< Tomahawk::album_ptr > albums;
QString artistString;
QString albumString;
foreach( const QVariant& av, albumList )
{
QVariantMap m = av.toMap();
artistString = m.value( "artist" ).toString().trimmed();
albumString = m.value( "album" ).toString().trimmed();
if ( artistString.isEmpty() || albumString.isEmpty() )
continue;
albums << Tomahawk::Album::get( Tomahawk::Artist::get( artistString ), albumString );
}
return albums;
}
QList< Tomahawk::result_ptr >
ScriptAccount::parseResultVariantList( const QVariantList& reslist )
{
QList< Tomahawk::result_ptr > results;
foreach( const QVariant& rv, reslist )
{
QVariantMap m = rv.toMap();
const QString artistString = m.value("artist").toString().trimmed();
const QString trackString = m.value("track").toString().trimmed();
if ( artistString.isEmpty() || trackString.isEmpty() )
{
tLog() << Q_FUNC_INFO << "Could not parse Track" << m;
continue;
}
int duration = m.value( "duration", 0 ).toInt();
if ( duration <= 0 && m.contains( "durationString" ) )
{
@@ -338,8 +270,8 @@ ScriptAccount::parseResultVariantList( const QVariantList& reslist )
duration = time.secsTo( QTime( 0, 0 ) ) * -1;
}
Tomahawk::track_ptr track = Tomahawk::Track::get( artistString,
trackString,
Tomahawk::track_ptr track = Tomahawk::Track::get( m.value( "artist" ).toString(),
m.value( "track" ).toString(),
m.value( "album" ).toString(),
m.value( "albumArtist" ).toString(),
duration,
@@ -394,6 +326,21 @@ 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;
}
@@ -401,29 +348,8 @@ ScriptAccount::parseResultVariantList( const QVariantList& reslist )
}
ScriptJob*
ScriptAccount::resolve( const scriptobject_ptr& scriptObject, const query_ptr& query, const QString& resolveType )
QSharedPointer< ScriptCollection >
ScriptAccount::scriptCollection( const QString& id ) const
{
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;
return m_collectionFactory->scriptPlugins().value( id );
}

View File

@@ -65,24 +65,18 @@ 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 );
virtual void showDebugger();
// helpers
QList< Tomahawk::artist_ptr > parseArtistVariantList( const QVariantList& artistList );
QList< Tomahawk::album_ptr > parseAlbumVariantList( const QVariantList& albumList );
QList< Tomahawk::result_ptr > parseResultVariantList( const QVariantList& reslist );
ScriptJob* resolve( const scriptobject_ptr& scriptObject, const query_ptr& query, const QString& resolveType );
QSharedPointer< ScriptCollection > scriptCollection( const QString& id ) const;
private slots:
void onJobDeleted( const QString& jobId );

View File

@@ -26,10 +26,7 @@
#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>
@@ -226,15 +223,6 @@ 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 )
@@ -338,58 +326,3 @@ 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();
}

View File

@@ -91,15 +91,8 @@ 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;

View File

@@ -28,8 +28,6 @@
#include "utils/Logger.h"
#include "../Result.h"
#include <QtConcurrentRun>
using namespace Tomahawk;
ScriptCommand_AllTracks::ScriptCommand_AllTracks( const Tomahawk::collection_ptr& collection,
@@ -119,22 +117,20 @@ ScriptCommand_AllTracks::onTracksJobDone( const QVariantMap& result )
QSharedPointer< ScriptCollection > collection = m_collection.objectCast< ScriptCollection >();
Q_ASSERT( !collection.isNull() );
QtConcurrent::run( [] ( ScriptCommand_AllTracks* t, ScriptJob* job, const QVariantMap& result, const QSharedPointer< ScriptCollection >& collection )
QList< Tomahawk::result_ptr > t = collection->scriptAccount()->parseResultVariantList( result[ "results"].toList() );
QList< Tomahawk::query_ptr > queries;
foreach ( const Tomahawk::result_ptr& result, t )
{
QList< Tomahawk::result_ptr > results = collection->scriptAccount()->parseResultVariantList( result[ "tracks" ].toList() );
result->setResolvedByCollection( m_collection );
queries.append( result->toQuery() );
}
QList< Tomahawk::query_ptr > queries;
foreach ( const Tomahawk::result_ptr& result, results )
{
result->setResolvedByCollection( collection );
queries.append( result->toQuery() );
}
tDebug() << Q_FUNC_INFO << "about to push" << queries.count() << "tracks";
tDebug() << Q_FUNC_INFO << "about to push" << queries.count() << "tracks";
emit tracks( queries );
emit done();
emit t->tracks( queries );
emit t->done();
job->deleteLater();
}, this, job, result, collection );
job->deleteLater();
}

View File

@@ -21,7 +21,7 @@
#include "ScriptEngine.h"
#include "jobview/ScriptErrorStatusMessage.h"
#include "jobview/ErrorStatusMessage.h"
#include "jobview/JobStatusModel.h"
#include "jobview/JobStatusView.h"
#include "utils/Logger.h"
@@ -51,13 +51,13 @@ ScriptEngine::ScriptEngine( JSAccount* parent )
settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true );
settings()->setOfflineStorageDefaultQuota(100 * 1024 * 1024 /* 100 Mb */);
settings()->setOfflineWebApplicationCacheQuota(100 * 1024 * 1024 /* 100 Mb */);
settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
// HACK
QStringList cmdArgs = QCoreApplication::instance()->arguments();
int position = cmdArgs.indexOf( "--show-inspector" ) + 1;
if ( position > 0 && !cmdArgs.at( position ).isEmpty() && parent->name().contains( cmdArgs.at( position ), Qt::CaseInsensitive ) ) {
QMetaObject::invokeMethod( this, "showWebInspector", Qt::QueuedConnection );
settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
QMetaObject::invokeMethod( this, "initWebInspector", Qt::QueuedConnection );
}
// Tomahawk is not a user agent
@@ -74,13 +74,24 @@ ScriptEngine::ScriptEngine( JSAccount* parent )
}
void
ScriptEngine::initWebInspector()
{
m_webInspector.reset( new QWebInspector() );
m_webInspector->setPage( this );
m_webInspector->setMinimumWidth( 800 );
m_webInspector->setMinimumHeight( 600 );
m_webInspector->show();
}
void
ScriptEngine::javaScriptConsoleMessage( const QString& message, int lineNumber, const QString& sourceID )
{
tLog() << "JAVASCRIPT:" << QString( "%1:%2" ).arg( m_scriptPath ).arg( lineNumber ) << message << sourceID;
#ifdef QT_DEBUG
QFileInfo scriptPath( m_scriptPath );
JobStatusView::instance()->model()->addJob( new ScriptErrorStatusMessage( tr( "%1:%2 %3" ).arg( scriptPath.fileName() ).arg( lineNumber ).arg( message ), m_parent ) );
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Resolver Error: %1:%2 %3" ).arg( scriptPath.fileName() ).arg( lineNumber ).arg( message ) ) );
#endif
}
@@ -137,21 +148,6 @@ ScriptEngine::setScriptPath( const QString& scriptPath )
}
void
ScriptEngine::showWebInspector()
{
if ( m_webInspector.isNull() )
{
m_webInspector.reset( new QWebInspector() );
m_webInspector->setPage( this );
m_webInspector->setMinimumWidth( 800 );
m_webInspector->setMinimumHeight( 600 );
}
m_webInspector->show();
}
bool
ScriptEngine::shouldInterruptJavaScript()
{

View File

@@ -49,13 +49,13 @@ public:
public slots:
bool shouldInterruptJavaScript();
void showWebInspector();
protected:
virtual void javaScriptConsoleMessage( const QString& message, int lineNumber, const QString& sourceID );
private slots:
void sslErrorHandler( QNetworkReply* qnr, const QList<QSslError>& errlist );
void initWebInspector();
private:
JSAccount* m_parent;

View File

@@ -19,7 +19,6 @@
#include "SourceList.h"
#include "../ScriptAccount.h"
#include "../../Pipeline.h"
using namespace Tomahawk;
@@ -30,14 +29,12 @@ 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 )

View File

@@ -25,14 +25,14 @@ using namespace Tomahawk;
void
ScriptInfoPluginFactory::addPlugin( const QSharedPointer< ScriptInfoPlugin >& infoPlugin ) const
{
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin );
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin.data() );
}
void
ScriptInfoPluginFactory::removePlugin( const QSharedPointer< ScriptInfoPlugin >& infoPlugin ) const
{
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin );
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin.data() );
}
@@ -42,10 +42,10 @@ ScriptInfoPluginFactory::createPlugin( const scriptobject_ptr& object, ScriptAcc
// create infoplugin instance
ScriptInfoPlugin* scriptInfoPlugin = new ScriptInfoPlugin( object, scriptAccount->name() );
QSharedPointer< ScriptInfoPlugin > infoPlugin( scriptInfoPlugin );
Tomahawk::InfoSystem::InfoPluginPtr infoPlugin( scriptInfoPlugin );
// move it to infosystem thread
infoPlugin->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
return infoPlugin;
return QSharedPointer< ScriptInfoPlugin >( scriptInfoPlugin );
}

View File

@@ -320,11 +320,11 @@ filesizeToString( unsigned int size )
if ( mb )
{
return QString( "%1.%2 MB" ).arg( mb ).arg( int( ( kb % 1024 ) / 102.4 ) );
return QString( "%1.%2 Mb" ).arg( mb ).arg( int( ( kb % 1024 ) / 102.4 ) );
}
else if ( kb )
{
return QString( "%1 KB" ).arg( kb );
return QString( "%1 Kb" ).arg( kb );
}
else
return QString::number( size );

View File

@@ -121,7 +121,7 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget*
ui->biography->setObjectName( "biography" );
ui->biography->setContentsMargins( 0, 0, 0, 0 );
ui->biography->page()->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
ui->biography->page()->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAsNeeded );
ui->biography->page()->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
ui->biography->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
ui->biography->installEventFilter( this );

View File

@@ -62,8 +62,6 @@ CollectionViewPage::CollectionViewPage( const Tomahawk::collection_ptr& collecti
m_columnView->proxyModel()->setStyle( PlayableProxyModel::SingleColumn );
PlayableProxyModel* trackViewProxyModel = m_trackView->proxyModel();
if ( collection->backendType() == Collection::ScriptCollectionType )
{
m_trackView->proxyModel()->setStyle( PlayableProxyModel::Locker );
@@ -72,12 +70,6 @@ CollectionViewPage::CollectionViewPage( const Tomahawk::collection_ptr& collecti
{
m_trackView->proxyModel()->setStyle( PlayableProxyModel::Collection );
}
// mapSourceColumnToColumn depends on the just set PlayableProxyModel::PlayableItemStyle
m_trackView->setColumnHidden( trackViewProxyModel->mapSourceColumnToColumn( PlayableModel::Composer ), true );
m_trackView->setColumnHidden( trackViewProxyModel->mapSourceColumnToColumn( PlayableModel::Origin ), true );
m_trackView->setColumnHidden( trackViewProxyModel->mapSourceColumnToColumn( PlayableModel::Score ), true );
m_trackView->setColumnHidden( trackViewProxyModel->mapSourceColumnToColumn( PlayableModel::Bitrate ), true );
m_trackView->setGuid( QString( "trackview/flat" ) );

View File

@@ -372,18 +372,13 @@ SearchWidget::onAlbumsFound( const QList<Tomahawk::album_ptr>& albums )
int distance = TomahawkUtils::levenshtein( m_search, album->name() );
int maxlen = qMax( m_search.length(), album->name().length() );
float scoreAlbum = (float)( maxlen - distance ) / maxlen;
float score = (float)( maxlen - distance ) / maxlen;
distance = TomahawkUtils::levenshtein( m_search, album->artist()->name() );
maxlen = qMax( m_search.length(), album->artist()->name().length() );
float scoreArtist = (float)( maxlen - distance ) / maxlen;
float scoreMax = qMax( scoreAlbum, scoreArtist );
if ( scoreMax <= 0.1 )
if ( score <= 0.1 )
continue;
m_albums.insert( album, scoreMax );
// tDebug() << Q_FUNC_INFO << "found album:" << album->name() << "scoreMax:" << scoreMax;
m_albums.insert( album, score );
// tDebug() << Q_FUNC_INFO << "found album:" << album->name() << "score:" << score;
}
// updateAlbums();

View File

@@ -85,7 +85,7 @@ ImageButton::paintEvent( QPaintEvent* event )
p.setClipRect( event->rect() );
QIcon::Mode mode = isDown()
? QIcon::Selected
? QIcon::Active
: QIcon::Normal;
QIcon::State state = isChecked()

View File

@@ -310,9 +310,8 @@ 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() ) );
setUpdatesEnabled( false );
ui->trackLabel->setResult( result );
ui->artistLabel->setResult( result );
ui->trackLabel->setResult( result );
const QString duration = TomahawkUtils::timeToString( result.data()->track()->duration() );
ui->timeLabel->setFixedWidth( ui->timeLabel->fontMetrics().width( QString( duration.length(), QChar( '0' ) ) ) );
@@ -371,7 +370,6 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr result )
setCover();
setSocialActions();
setUpdatesEnabled( true );
}

View File

@@ -1,4 +1,4 @@
set(TOMAHAWK_APPLICATION_TARGET "tomahawk-bin")
set(TOMAHAWK_APPLICATION_TARGET "tomahahawk-bin")
include( ECMAddAppIcon )
@@ -146,14 +146,8 @@ 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" )

View File

@@ -96,6 +96,12 @@
#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;
@@ -105,6 +111,10 @@ 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 )
@@ -144,7 +154,9 @@ 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" ) )
@@ -525,12 +537,61 @@ TomahawkWindow::setupUpdateCheck()
#ifdef Q_OS_WIN
void
bool
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" ) );
@@ -564,84 +625,26 @@ 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 )
}
void
TomahawkWindow::updatePreview()
#if QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
HICON
TomahawkWindow::thumbIcon( TomahawkUtils::ImageType type )
{
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() );
static QMap<TomahawkUtils::ImageType,HICON> thumbIcons;
if ( !thumbIcons.contains( type ) )
{
QPixmap pix ( TomahawkUtils::defaultPixmap(type , TomahawkUtils::Original, QSize( 40, 40 ) ) );
thumbIcons[type] = pix.toWinHICON();
}
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 );
return thumbIcons[type];
}
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" ) );
}
}
#else
QIcon
TomahawkWindow::thumbIcon(TomahawkUtils::ImageType type)
@@ -649,6 +652,8 @@ TomahawkWindow::thumbIcon(TomahawkUtils::ImageType type)
return TomahawkUtils::defaultPixmap( type , TomahawkUtils::Original, QSize( 40, 40 ) );
}
#endif//QT_VERSION < QT_VERSION_CHECK( 5, 2, 0 )
#endif
@@ -839,6 +844,51 @@ 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 )
{
@@ -846,8 +896,48 @@ TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
#ifndef Q_OS_WIN
Q_UNUSED(newState);
#else
updatePreview();
#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
QWinThumbnailToolButton *play = m_taskbarList->buttons()[ TP_PLAY_PAUSE ];
switch ( newState )
{
@@ -856,6 +946,7 @@ TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
play->setIcon( thumbIcon(TomahawkUtils::PauseButton) );
play->setToolTip( tr( "Pause" ) );
updateWindowsLoveButton();
}
break;
@@ -885,9 +976,57 @@ 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 )
{

View File

@@ -37,9 +37,11 @@
#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
{
@@ -90,6 +92,10 @@ 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();
@@ -149,11 +155,7 @@ private slots:
void toggleLoved();
void audioStateChanged( AudioState newState, AudioState oldState );
#ifdef Q_OS_WIN
void updateWindowsLoveButton();
void updatePreview();
#endif
private:
void loadSettings();
@@ -171,9 +173,16 @@ private:
void importPlaylist( const QString& url, bool autoUpdate );
#ifdef Q_OS_WIN
void setupWindowsButtons();
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
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

View File

@@ -37,7 +37,6 @@
#include "sip/SipPlugin.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h"
#include "Pipeline.h"
#include <QApplication>
#include <QClipboard>
@@ -124,20 +123,6 @@ 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 );
}

View File

@@ -59,8 +59,6 @@
#include "jobview/ErrorStatusMessage.h"
#include "utils/NetworkAccessManager.h"
#include "utils/NetworkProxyFactory.h"
#include "resolvers/JSAccount.h"
#include "resolvers/JSResolver.h"
#include <QDesktopServices>
#include <QFileDialog>
@@ -70,7 +68,6 @@
#include <QVBoxLayout>
#include <QSizeGrip>
#include <QToolBar>
#include <QMenu>
using namespace Tomahawk;
using namespace Accounts;
@@ -90,7 +87,6 @@ SettingsDialog::SettingsDialog(QObject *parent )
, m_restartRequired( false )
, m_accountModel( 0 )
, m_sipSpinner( 0 )
, m_contextMenu( 0 )
{
m_accountsWidget->setFont( TomahawkUtils::systemFont() );
m_collectionWidget->setFont( TomahawkUtils::systemFont() );
@@ -148,12 +144,6 @@ SettingsDialog::SettingsDialog(QObject *parent )
m_accountsWidgetUi->accountsView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
m_accountsWidgetUi->accountsView->setMouseTracking( true );
m_contextMenu = new QMenu( m_accountsWidgetUi->accountsView );
m_contextMenu->setFont( TomahawkUtils::systemFont() );
connect( m_accountsWidgetUi->accountsView, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) );
QAction* showDebuggerAction = m_contextMenu->addAction( tr( "Open Account &Debugger..." ) );
connect( showDebuggerAction, SIGNAL( triggered(bool) ), SLOT( onShowDebuggerForSelectedAccount() ) );
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) );
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::AccountFactory* ) ), SLOT( openAccountFactoryConfig( Tomahawk::Accounts::AccountFactory* ) ) );
connect( accountDelegate, SIGNAL( update( QModelIndex ) ), m_accountsWidgetUi->accountsView, SLOT( update( QModelIndex ) ) );
@@ -390,34 +380,6 @@ SettingsDialog::onRejected()
}
void
SettingsDialog::onCustomContextMenu( const QPoint& point )
{
QModelIndex index = m_accountsWidgetUi->accountsView->indexAt( point );
if ( !index.isValid() )
return;
// HACK until there is a proper ScriptAccount
ResolverAccount* account = qobject_cast< ResolverAccount* >( m_accountProxy->data( index, AccountModel::AccountData ).value< Tomahawk::Accounts::Account* >() );
if ( !account )
return;
Tomahawk::JSResolver* jsResolver = qobject_cast< Tomahawk::JSResolver* >( account->resolver() );
if ( !jsResolver )
return;
m_contextMenu->exec( m_accountsWidgetUi->accountsView->mapToGlobal( point ) );
}
void
SettingsDialog::onShowDebuggerForSelectedAccount()
{
ResolverAccount* account = m_accountProxy->data( m_accountsWidgetUi->accountsView->currentIndex(), AccountModel::AccountData ).value< ResolverAccount* >();
Tomahawk::JSResolver* jsResolver = qobject_cast< Tomahawk::JSResolver* >( account->resolver() );
jsResolver->scriptAccount()->showDebugger();
}
void
SettingsDialog::changeEvent( QEvent *e )
{

View File

@@ -37,7 +37,6 @@ class SipPlugin;
class ResolversModel;
class QNetworkReply;
class QToolbarTabDialog;
class QMenu;
namespace Ui
{
@@ -131,9 +130,6 @@ private slots:
void saveSettings();
void onRejected();
void onCustomContextMenu( const QPoint& point );
void onShowDebuggerForSelectedAccount();
private:
Ui_Settings_Accounts* m_accountsWidgetUi;
QWidget* m_accountsWidget;
@@ -156,7 +152,6 @@ private:
Tomahawk::Accounts::AccountModelFilterProxy* m_accountProxy;
QHash<QString, QString> m_downloadsFormats;
AnimatedSpinner* m_sipSpinner;
QMenu* m_contextMenu;
};
#endif // SETTINGSDIALOG_H

View File

@@ -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/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" ) );
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" ) );
QObject::connect( backItem, SIGNAL( activated() ), ViewManager::instance(), SLOT( historyBack() ) );
QObject::connect( forwardItem, SIGNAL( activated() ), ViewManager::instance(), SLOT( historyForward() ) );
@@ -381,12 +381,6 @@ 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 );

Some files were not shown because too many files have changed in this diff Show More